1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "PrintTarget.h" 7 8 #include "cairo.h" 9 #include "mozilla/gfx/2D.h" 10 #include "mozilla/gfx/Logging.h" 11 12 namespace mozilla { 13 namespace gfx { 14 15 PrintTarget::PrintTarget(cairo_surface_t* aCairoSurface, const IntSize& aSize) 16 : mCairoSurface(aCairoSurface) 17 , mSize(aSize) 18 , mIsFinished(false) 19 #ifdef DEBUG 20 , mHasActivePage(false) 21 #endif 22 23 { 24 #if 0 25 // aCairoSurface is null when our PrintTargetThebes subclass's ctor calls us. 26 // Once PrintTargetThebes is removed, enable this assertion. 27 MOZ_ASSERT(aCairoSurface && !cairo_surface_status(aCairoSurface), 28 "CreateOrNull factory methods should not call us without a " 29 "valid cairo_surface_t*"); 30 #endif 31 32 // CreateOrNull factory methods hand over ownership of aCairoSurface, 33 // so we don't call cairo_surface_reference(aSurface) here. 34 35 // This code was copied from gfxASurface::Init: 36 #ifdef MOZ_TREE_CAIRO 37 if (mCairoSurface && 38 cairo_surface_get_content(mCairoSurface) != CAIRO_CONTENT_COLOR) { 39 cairo_surface_set_subpixel_antialiasing(mCairoSurface, 40 CAIRO_SUBPIXEL_ANTIALIASING_DISABLED); 41 } 42 #endif 43 } 44 45 PrintTarget::~PrintTarget() 46 { 47 // null surfaces are allowed here 48 cairo_surface_destroy(mCairoSurface); 49 mCairoSurface = nullptr; 50 } 51 52 already_AddRefed<DrawTarget> 53 PrintTarget::MakeDrawTarget(const IntSize& aSize, 54 DrawEventRecorder* aRecorder) 55 { 56 MOZ_ASSERT(mCairoSurface, 57 "We shouldn't have been constructed without a cairo surface"); 58 59 // This should not be called outside of BeginPage()/EndPage() calls since 60 // some backends can only provide a valid DrawTarget at that time. 61 MOZ_ASSERT(mHasActivePage, "We can't guarantee a valid DrawTarget"); 62 63 if (cairo_surface_status(mCairoSurface)) { 64 return nullptr; 65 } 66 67 // Note than aSize may not be the same as mSize (the size of mCairoSurface). 68 // See the comments in our header. If the sizes are different a clip will 69 // be applied to mCairoSurface. 70 RefPtr<DrawTarget> dt = 71 Factory::CreateDrawTargetForCairoSurface(mCairoSurface, aSize); 72 if (!dt || !dt->IsValid()) { 73 return nullptr; 74 } 75 76 if (aRecorder) { 77 dt = CreateRecordingDrawTarget(aRecorder, dt); 78 if (!dt || !dt->IsValid()) { 79 return nullptr; 80 } 81 } 82 83 return dt.forget(); 84 } 85 86 already_AddRefed<DrawTarget> 87 PrintTarget::GetReferenceDrawTarget(DrawEventRecorder* aRecorder) 88 { 89 if (!mRefDT) { 90 IntSize size(1, 1); 91 92 cairo_surface_t* surface = 93 cairo_surface_create_similar(mCairoSurface, 94 cairo_surface_get_content(mCairoSurface), 95 size.width, size.height); 96 97 if (cairo_surface_status(surface)) { 98 return nullptr; 99 } 100 101 RefPtr<DrawTarget> dt = 102 Factory::CreateDrawTargetForCairoSurface(surface, size); 103 104 // The DT addrefs the surface, so we need drop our own reference to it: 105 cairo_surface_destroy(surface); 106 107 if (!dt || !dt->IsValid()) { 108 return nullptr; 109 } 110 111 if (aRecorder) { 112 dt = CreateRecordingDrawTarget(aRecorder, dt); 113 if (!dt || !dt->IsValid()) { 114 return nullptr; 115 } 116 } 117 118 mRefDT = dt.forget(); 119 } 120 return do_AddRef(mRefDT); 121 } 122 123 already_AddRefed<DrawTarget> 124 PrintTarget::CreateRecordingDrawTarget(DrawEventRecorder* aRecorder, 125 DrawTarget* aDrawTarget) 126 { 127 MOZ_ASSERT(aRecorder); 128 MOZ_ASSERT(aDrawTarget); 129 130 RefPtr<DrawTarget> dt; 131 132 if (aRecorder) { 133 // It doesn't really matter what we pass as the DrawTarget here. 134 dt = gfx::Factory::CreateRecordingDrawTarget(aRecorder, aDrawTarget); 135 } 136 137 if (!dt || !dt->IsValid()) { 138 gfxCriticalNote 139 << "Failed to create a recording DrawTarget for PrintTarget"; 140 return nullptr; 141 } 142 143 return dt.forget(); 144 } 145 146 void 147 PrintTarget::Finish() 148 { 149 if (mIsFinished) { 150 return; 151 } 152 mIsFinished = true; 153 154 // null surfaces are allowed here 155 cairo_surface_finish(mCairoSurface); 156 } 157 158 } // namespace gfx 159 } // namespace mozilla 160