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 "gfxDrawable.h"
7 : #include "gfxASurface.h"
8 : #include "gfxContext.h"
9 : #include "gfxPlatform.h"
10 : #include "gfx2DGlue.h"
11 : #ifdef MOZ_X11
12 : #include "cairo.h"
13 : #include "gfxXlibSurface.h"
14 : #endif
15 : #include "mozilla/gfx/Logging.h"
16 :
17 : using namespace mozilla;
18 : using namespace mozilla::gfx;
19 :
20 108 : gfxSurfaceDrawable::gfxSurfaceDrawable(SourceSurface* aSurface,
21 : const IntSize aSize,
22 108 : const gfxMatrix aTransform)
23 : : gfxDrawable(aSize)
24 : , mSourceSurface(aSurface)
25 108 : , mTransform(aTransform)
26 : {
27 108 : if (!mSourceSurface) {
28 0 : gfxWarning() << "Creating gfxSurfaceDrawable with null SourceSurface";
29 : }
30 108 : }
31 :
32 : bool
33 0 : gfxSurfaceDrawable::DrawWithSamplingRect(DrawTarget* aDrawTarget,
34 : CompositionOp aOp,
35 : AntialiasMode aAntialiasMode,
36 : const gfxRect& aFillRect,
37 : const gfxRect& aSamplingRect,
38 : ExtendMode aExtendMode,
39 : const SamplingFilter aSamplingFilter,
40 : gfxFloat aOpacity)
41 : {
42 0 : if (!mSourceSurface) {
43 0 : return true;
44 : }
45 :
46 : // When drawing with CLAMP we can expand the sampling rect to the nearest pixel
47 : // without changing the result.
48 0 : IntRect intRect = IntRect::RoundOut(aSamplingRect.x, aSamplingRect.y,
49 0 : aSamplingRect.width, aSamplingRect.height);
50 :
51 0 : IntSize size = mSourceSurface->GetSize();
52 0 : if (!IntRect(IntPoint(), size).Contains(intRect)) {
53 0 : return false;
54 : }
55 :
56 : DrawInternal(aDrawTarget, aOp, aAntialiasMode, aFillRect, intRect,
57 0 : ExtendMode::CLAMP, aSamplingFilter, aOpacity, gfxMatrix());
58 0 : return true;
59 : }
60 :
61 : bool
62 108 : gfxSurfaceDrawable::Draw(gfxContext* aContext,
63 : const gfxRect& aFillRect,
64 : ExtendMode aExtendMode,
65 : const SamplingFilter aSamplingFilter,
66 : gfxFloat aOpacity,
67 : const gfxMatrix& aTransform)
68 :
69 : {
70 108 : if (!mSourceSurface) {
71 0 : return true;
72 : }
73 :
74 108 : DrawInternal(aContext->GetDrawTarget(), aContext->CurrentOp(),
75 216 : aContext->CurrentAntialiasMode(), aFillRect, IntRect(),
76 108 : aExtendMode, aSamplingFilter, aOpacity, aTransform);
77 108 : return true;
78 : }
79 :
80 : void
81 108 : gfxSurfaceDrawable::DrawInternal(DrawTarget* aDrawTarget,
82 : CompositionOp aOp,
83 : AntialiasMode aAntialiasMode,
84 : const gfxRect& aFillRect,
85 : const IntRect& aSamplingRect,
86 : ExtendMode aExtendMode,
87 : const SamplingFilter aSamplingFilter,
88 : gfxFloat aOpacity,
89 : const gfxMatrix& aTransform)
90 : {
91 108 : Matrix patternTransform = ToMatrix(aTransform * mTransform);
92 108 : patternTransform.Invert();
93 :
94 : SurfacePattern pattern(mSourceSurface, aExtendMode,
95 216 : patternTransform, aSamplingFilter, aSamplingRect);
96 :
97 108 : Rect fillRect = ToRect(aFillRect);
98 :
99 108 : if (aOp == CompositionOp::OP_SOURCE && aOpacity == 1.0) {
100 : // Emulate cairo operator source which is bound by mask!
101 0 : aDrawTarget->ClearRect(fillRect);
102 0 : aDrawTarget->FillRect(fillRect, pattern);
103 : } else {
104 : aDrawTarget->FillRect(fillRect, pattern,
105 108 : DrawOptions(aOpacity, aOp, aAntialiasMode));
106 : }
107 108 : }
108 :
109 18 : gfxCallbackDrawable::gfxCallbackDrawable(gfxDrawingCallback* aCallback,
110 18 : const IntSize aSize)
111 : : gfxDrawable(aSize)
112 18 : , mCallback(aCallback)
113 : {
114 18 : }
115 :
116 : already_AddRefed<gfxSurfaceDrawable>
117 0 : gfxCallbackDrawable::MakeSurfaceDrawable(gfxContext *aContext, const SamplingFilter aSamplingFilter)
118 : {
119 : SurfaceFormat format =
120 0 : gfxPlatform::GetPlatform()->Optimal2DFormatForContent(gfxContentType::COLOR_ALPHA);
121 : RefPtr<DrawTarget> dt =
122 0 : aContext->GetDrawTarget()->CreateSimilarDrawTarget(mSize, format);
123 :
124 0 : if (!dt || !dt->IsValid())
125 0 : return nullptr;
126 :
127 0 : RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
128 0 : MOZ_ASSERT(ctx); // already checked for target above
129 0 : Draw(ctx, gfxRect(0, 0, mSize.width, mSize.height), ExtendMode::CLAMP,
130 0 : aSamplingFilter);
131 :
132 0 : RefPtr<SourceSurface> surface = dt->Snapshot();
133 0 : if (surface) {
134 0 : RefPtr<gfxSurfaceDrawable> drawable = new gfxSurfaceDrawable(surface, mSize);
135 0 : return drawable.forget();
136 : }
137 0 : return nullptr;
138 : }
139 :
140 : static bool
141 18 : IsRepeatingExtendMode(ExtendMode aExtendMode)
142 : {
143 18 : switch (aExtendMode) {
144 : case ExtendMode::REPEAT:
145 : case ExtendMode::REPEAT_X:
146 : case ExtendMode::REPEAT_Y:
147 0 : return true;
148 : default:
149 18 : return false;
150 : }
151 : }
152 :
153 : bool
154 18 : gfxCallbackDrawable::Draw(gfxContext* aContext,
155 : const gfxRect& aFillRect,
156 : ExtendMode aExtendMode,
157 : const SamplingFilter aSamplingFilter,
158 : gfxFloat aOpacity,
159 : const gfxMatrix& aTransform)
160 : {
161 18 : if ((IsRepeatingExtendMode(aExtendMode) || aOpacity != 1.0 || aContext->CurrentOp() != CompositionOp::OP_OVER) &&
162 0 : !mSurfaceDrawable) {
163 0 : mSurfaceDrawable = MakeSurfaceDrawable(aContext, aSamplingFilter);
164 : }
165 :
166 18 : if (mSurfaceDrawable)
167 0 : return mSurfaceDrawable->Draw(aContext, aFillRect, aExtendMode,
168 : aSamplingFilter,
169 0 : aOpacity, aTransform);
170 :
171 18 : if (mCallback)
172 18 : return (*mCallback)(aContext, aFillRect, aSamplingFilter, aTransform);
173 :
174 0 : return false;
175 : }
176 :
177 0 : gfxPatternDrawable::gfxPatternDrawable(gfxPattern* aPattern,
178 0 : const IntSize aSize)
179 : : gfxDrawable(aSize)
180 0 : , mPattern(aPattern)
181 : {
182 0 : }
183 :
184 : gfxPatternDrawable::~gfxPatternDrawable() = default;
185 :
186 : class DrawingCallbackFromDrawable : public gfxDrawingCallback {
187 : public:
188 0 : explicit DrawingCallbackFromDrawable(gfxDrawable* aDrawable)
189 0 : : mDrawable(aDrawable) {
190 0 : NS_ASSERTION(aDrawable, "aDrawable is null!");
191 0 : }
192 :
193 0 : ~DrawingCallbackFromDrawable() override = default;
194 :
195 0 : bool operator()(gfxContext* aContext,
196 : const gfxRect& aFillRect,
197 : const SamplingFilter aSamplingFilter,
198 : const gfxMatrix& aTransform = gfxMatrix()) override
199 : {
200 0 : return mDrawable->Draw(aContext, aFillRect, ExtendMode::CLAMP,
201 : aSamplingFilter, 1.0,
202 0 : aTransform);
203 : }
204 : private:
205 : RefPtr<gfxDrawable> mDrawable;
206 : };
207 :
208 : already_AddRefed<gfxCallbackDrawable>
209 0 : gfxPatternDrawable::MakeCallbackDrawable()
210 : {
211 : RefPtr<gfxDrawingCallback> callback =
212 0 : new DrawingCallbackFromDrawable(this);
213 : RefPtr<gfxCallbackDrawable> callbackDrawable =
214 0 : new gfxCallbackDrawable(callback, mSize);
215 0 : return callbackDrawable.forget();
216 : }
217 :
218 : bool
219 0 : gfxPatternDrawable::Draw(gfxContext* aContext,
220 : const gfxRect& aFillRect,
221 : ExtendMode aExtendMode,
222 : const SamplingFilter aSamplingFilter,
223 : gfxFloat aOpacity,
224 : const gfxMatrix& aTransform)
225 : {
226 0 : DrawTarget& aDrawTarget = *aContext->GetDrawTarget();
227 :
228 0 : if (!mPattern)
229 0 : return false;
230 :
231 0 : if (IsRepeatingExtendMode(aExtendMode)) {
232 : // We can't use mPattern directly: We want our repeated tiles to have
233 : // the size mSize, which might not be the case in mPattern.
234 : // So we need to draw mPattern into a surface of size mSize, create
235 : // a pattern from the surface and draw that pattern.
236 : // gfxCallbackDrawable and gfxSurfaceDrawable already know how to do
237 : // those things, so we use them here. Drawing mPattern into the surface
238 : // will happen through this Draw() method with aRepeat = false.
239 0 : RefPtr<gfxCallbackDrawable> callbackDrawable = MakeCallbackDrawable();
240 0 : return callbackDrawable->Draw(aContext, aFillRect, aExtendMode,
241 : aSamplingFilter,
242 0 : aOpacity, aTransform);
243 : }
244 :
245 0 : gfxMatrix oldMatrix = mPattern->GetMatrix();
246 0 : mPattern->SetMatrix(aTransform * oldMatrix);
247 0 : DrawOptions drawOptions(aOpacity);
248 0 : aDrawTarget.FillRect(ToRect(aFillRect),
249 0 : *mPattern->GetPattern(&aDrawTarget), drawOptions);
250 0 : mPattern->SetMatrix(oldMatrix);
251 0 : return true;
252 : }
|