Line data Source code
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 : #ifdef CAIRO_HAS_QUARTZ_SURFACE
10 : #include "cairo-quartz.h"
11 : #endif
12 : #ifdef CAIRO_HAS_WIN32_SURFACE
13 : #include "cairo-win32.h"
14 : #endif
15 : #include "mozilla/gfx/2D.h"
16 : #include "mozilla/gfx/HelpersCairo.h"
17 : #include "mozilla/gfx/Logging.h"
18 :
19 : namespace mozilla {
20 : namespace gfx {
21 :
22 0 : PrintTarget::PrintTarget(cairo_surface_t* aCairoSurface, const IntSize& aSize)
23 : : mCairoSurface(aCairoSurface)
24 : , mSize(aSize)
25 : , mIsFinished(false)
26 : #ifdef DEBUG
27 : , mHasActivePage(false)
28 0 : , mRecorder(nullptr)
29 : #endif
30 :
31 : {
32 : #if 0
33 : // aCairoSurface is null when our PrintTargetThebes subclass's ctor calls us.
34 : // Once PrintTargetThebes is removed, enable this assertion.
35 : MOZ_ASSERT(aCairoSurface && !cairo_surface_status(aCairoSurface),
36 : "CreateOrNull factory methods should not call us without a "
37 : "valid cairo_surface_t*");
38 : #endif
39 :
40 : // CreateOrNull factory methods hand over ownership of aCairoSurface,
41 : // so we don't call cairo_surface_reference(aSurface) here.
42 :
43 : // This code was copied from gfxASurface::Init:
44 : #ifdef MOZ_TREE_CAIRO
45 0 : if (mCairoSurface &&
46 0 : cairo_surface_get_content(mCairoSurface) != CAIRO_CONTENT_COLOR) {
47 0 : cairo_surface_set_subpixel_antialiasing(mCairoSurface,
48 0 : CAIRO_SUBPIXEL_ANTIALIASING_DISABLED);
49 : }
50 : #endif
51 0 : }
52 :
53 0 : PrintTarget::~PrintTarget()
54 : {
55 : // null surfaces are allowed here
56 0 : cairo_surface_destroy(mCairoSurface);
57 0 : mCairoSurface = nullptr;
58 0 : }
59 :
60 : already_AddRefed<DrawTarget>
61 0 : PrintTarget::MakeDrawTarget(const IntSize& aSize,
62 : DrawEventRecorder* aRecorder)
63 : {
64 0 : MOZ_ASSERT(mCairoSurface,
65 : "We shouldn't have been constructed without a cairo surface");
66 :
67 : // This should not be called outside of BeginPage()/EndPage() calls since
68 : // some backends can only provide a valid DrawTarget at that time.
69 0 : MOZ_ASSERT(mHasActivePage, "We can't guarantee a valid DrawTarget");
70 :
71 0 : if (cairo_surface_status(mCairoSurface)) {
72 0 : return nullptr;
73 : }
74 :
75 : // Note than aSize may not be the same as mSize (the size of mCairoSurface).
76 : // See the comments in our header. If the sizes are different a clip will
77 : // be applied to mCairoSurface.
78 : RefPtr<DrawTarget> dt =
79 0 : Factory::CreateDrawTargetForCairoSurface(mCairoSurface, aSize);
80 0 : if (!dt || !dt->IsValid()) {
81 0 : return nullptr;
82 : }
83 :
84 0 : if (aRecorder) {
85 0 : dt = CreateWrapAndRecordDrawTarget(aRecorder, dt);
86 0 : if (!dt || !dt->IsValid()) {
87 0 : return nullptr;
88 : }
89 : }
90 :
91 0 : return dt.forget();
92 : }
93 :
94 : already_AddRefed<DrawTarget>
95 0 : PrintTarget::GetReferenceDrawTarget(DrawEventRecorder* aRecorder)
96 : {
97 0 : if (!mRefDT) {
98 0 : const IntSize size(1, 1);
99 :
100 : cairo_surface_t* similar;
101 0 : switch (cairo_surface_get_type(mCairoSurface)) {
102 : #ifdef CAIRO_HAS_WIN32_SURFACE
103 : case CAIRO_SURFACE_TYPE_WIN32:
104 : similar = cairo_win32_surface_create_with_dib(
105 : CairoContentToCairoFormat(cairo_surface_get_content(mCairoSurface)),
106 : size.width, size.height);
107 : break;
108 : #endif
109 : #ifdef CAIRO_HAS_QUARTZ_SURFACE
110 : case CAIRO_SURFACE_TYPE_QUARTZ:
111 : similar = cairo_quartz_surface_create_cg_layer(
112 : mCairoSurface, cairo_surface_get_content(mCairoSurface),
113 : size.width, size.height);
114 : break;
115 : #endif
116 : default:
117 0 : similar = cairo_surface_create_similar(
118 : mCairoSurface, cairo_surface_get_content(mCairoSurface),
119 0 : size.width, size.height);
120 0 : break;
121 : }
122 :
123 0 : if (cairo_surface_status(similar)) {
124 0 : return nullptr;
125 : }
126 :
127 : RefPtr<DrawTarget> dt =
128 0 : Factory::CreateDrawTargetForCairoSurface(similar, size);
129 :
130 : // The DT addrefs the surface, so we need drop our own reference to it:
131 0 : cairo_surface_destroy(similar);
132 :
133 0 : if (!dt || !dt->IsValid()) {
134 0 : return nullptr;
135 : }
136 0 : mRefDT = dt.forget();
137 : }
138 :
139 0 : if (aRecorder) {
140 0 : if (!mRecordingRefDT) {
141 0 : RefPtr<DrawTarget> dt = CreateWrapAndRecordDrawTarget(aRecorder, mRefDT);
142 0 : if (!dt || !dt->IsValid()) {
143 0 : return nullptr;
144 : }
145 0 : mRecordingRefDT = dt.forget();
146 : #ifdef DEBUG
147 0 : mRecorder = aRecorder;
148 : #endif
149 : }
150 : #ifdef DEBUG
151 : else {
152 0 : MOZ_ASSERT(aRecorder == mRecorder,
153 : "Caching mRecordingRefDT assumes the aRecorder is an invariant");
154 : }
155 : #endif
156 :
157 0 : return do_AddRef(mRecordingRefDT);
158 : }
159 :
160 0 : return do_AddRef(mRefDT);
161 : }
162 :
163 : /* static */ already_AddRefed<DrawTarget>
164 0 : PrintTarget::CreateWrapAndRecordDrawTarget(DrawEventRecorder* aRecorder,
165 : DrawTarget* aDrawTarget)
166 : {
167 0 : MOZ_ASSERT(aRecorder);
168 0 : MOZ_ASSERT(aDrawTarget);
169 :
170 0 : RefPtr<DrawTarget> dt;
171 :
172 0 : if (aRecorder) {
173 : // It doesn't really matter what we pass as the DrawTarget here.
174 0 : dt = gfx::Factory::CreateWrapAndRecordDrawTarget(aRecorder, aDrawTarget);
175 : }
176 :
177 0 : if (!dt || !dt->IsValid()) {
178 0 : gfxCriticalNote
179 0 : << "Failed to create a recording DrawTarget for PrintTarget";
180 0 : return nullptr;
181 : }
182 :
183 0 : return dt.forget();
184 : }
185 :
186 : void
187 0 : PrintTarget::Finish()
188 : {
189 0 : if (mIsFinished) {
190 0 : return;
191 : }
192 0 : mIsFinished = true;
193 :
194 : // null surfaces are allowed here
195 0 : cairo_surface_finish(mCairoSurface);
196 : }
197 :
198 : } // namespace gfx
199 : } // namespace mozilla
|