1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "BasicLayersImpl.h"
8 #include <new> // for operator new
9 #include "Layers.h" // for Layer, etc
10 #include "basic/BasicImplData.h" // for BasicImplData
11 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
12 #include "mozilla/DebugOnly.h" // for DebugOnly
13 #include "mozilla/layers/CompositorTypes.h"
14 #include "mozilla/layers/ISurfaceAllocator.h"
15 #include "AutoMaskData.h"
16
17 namespace mozilla {
18 namespace layers {
19
20 using namespace mozilla::gfx;
21
GetMaskData(Layer * aMaskLayer,const Point & aDeviceOffset,AutoMoz2DMaskData * aMaskData)22 bool GetMaskData(Layer* aMaskLayer, const Point& aDeviceOffset,
23 AutoMoz2DMaskData* aMaskData) {
24 if (aMaskLayer) {
25 RefPtr<SourceSurface> surface =
26 static_cast<BasicImplData*>(aMaskLayer->ImplData())
27 ->GetAsSourceSurface();
28 if (surface) {
29 Matrix transform;
30 Matrix4x4 effectiveTransform = aMaskLayer->GetEffectiveTransform();
31 DebugOnly<bool> maskIs2D = effectiveTransform.CanDraw2D(&transform);
32 NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
33 transform.PostTranslate(-aDeviceOffset.x, -aDeviceOffset.y);
34 aMaskData->Construct(transform, surface);
35 return true;
36 }
37 }
38 return false;
39 }
40
GetMaskForLayer(Layer * aLayer,Matrix * aMaskTransform)41 already_AddRefed<SourceSurface> GetMaskForLayer(Layer* aLayer,
42 Matrix* aMaskTransform) {
43 if (!aLayer->GetMaskLayer()) {
44 return nullptr;
45 }
46
47 MOZ_ASSERT(aMaskTransform);
48
49 AutoMoz2DMaskData mask;
50 if (GetMaskData(aLayer->GetMaskLayer(), Point(), &mask)) {
51 *aMaskTransform = mask.GetTransform();
52 RefPtr<SourceSurface> surf = mask.GetSurface();
53 return surf.forget();
54 }
55
56 return nullptr;
57 }
58
PaintWithMask(gfxContext * aContext,float aOpacity,Layer * aMaskLayer)59 void PaintWithMask(gfxContext* aContext, float aOpacity, Layer* aMaskLayer) {
60 AutoMoz2DMaskData mask;
61 if (GetMaskData(aMaskLayer, Point(), &mask)) {
62 aContext->SetMatrix(mask.GetTransform());
63 aContext->Mask(mask.GetSurface(), aOpacity);
64 return;
65 }
66
67 // if there is no mask, just paint normally
68 aContext->Paint(aOpacity);
69 }
70
FillRectWithMask(DrawTarget * aDT,const Rect & aRect,const DeviceColor & aColor,const DrawOptions & aOptions,SourceSurface * aMaskSource,const Matrix * aMaskTransform)71 void FillRectWithMask(DrawTarget* aDT, const Rect& aRect,
72 const DeviceColor& aColor, const DrawOptions& aOptions,
73 SourceSurface* aMaskSource,
74 const Matrix* aMaskTransform) {
75 if (aMaskSource && aMaskTransform) {
76 aDT->PushClipRect(aRect);
77 Matrix oldTransform = aDT->GetTransform();
78
79 aDT->SetTransform(*aMaskTransform);
80 aDT->MaskSurface(ColorPattern(aColor), aMaskSource, Point(), aOptions);
81 aDT->SetTransform(oldTransform);
82 aDT->PopClip();
83 return;
84 }
85
86 aDT->FillRect(aRect, ColorPattern(aColor), aOptions);
87 }
FillRectWithMask(DrawTarget * aDT,const gfx::Point & aDeviceOffset,const Rect & aRect,const DeviceColor & aColor,const DrawOptions & aOptions,Layer * aMaskLayer)88 void FillRectWithMask(DrawTarget* aDT, const gfx::Point& aDeviceOffset,
89 const Rect& aRect, const DeviceColor& aColor,
90 const DrawOptions& aOptions, Layer* aMaskLayer) {
91 AutoMoz2DMaskData mask;
92 if (GetMaskData(aMaskLayer, aDeviceOffset, &mask)) {
93 const Matrix& maskTransform = mask.GetTransform();
94 FillRectWithMask(aDT, aRect, aColor, aOptions, mask.GetSurface(),
95 &maskTransform);
96 return;
97 }
98
99 FillRectWithMask(aDT, aRect, aColor, aOptions);
100 }
101
FillRectWithMask(DrawTarget * aDT,const Rect & aRect,SourceSurface * aSurface,SamplingFilter aSamplingFilter,const DrawOptions & aOptions,ExtendMode aExtendMode,SourceSurface * aMaskSource,const Matrix * aMaskTransform,const Matrix * aSurfaceTransform)102 void FillRectWithMask(DrawTarget* aDT, const Rect& aRect,
103 SourceSurface* aSurface, SamplingFilter aSamplingFilter,
104 const DrawOptions& aOptions, ExtendMode aExtendMode,
105 SourceSurface* aMaskSource, const Matrix* aMaskTransform,
106 const Matrix* aSurfaceTransform) {
107 if (aMaskSource && aMaskTransform) {
108 aDT->PushClipRect(aRect);
109 Matrix oldTransform = aDT->GetTransform();
110
111 Matrix inverseMask = *aMaskTransform;
112 inverseMask.Invert();
113
114 Matrix transform = oldTransform * inverseMask;
115 if (aSurfaceTransform) {
116 transform = (*aSurfaceTransform) * transform;
117 }
118
119 SurfacePattern source(aSurface, aExtendMode, transform, aSamplingFilter);
120
121 aDT->SetTransform(*aMaskTransform);
122 aDT->MaskSurface(source, aMaskSource, Point(0, 0), aOptions);
123
124 aDT->SetTransform(oldTransform);
125 aDT->PopClip();
126 return;
127 }
128
129 aDT->FillRect(
130 aRect,
131 SurfacePattern(aSurface, aExtendMode,
132 aSurfaceTransform ? (*aSurfaceTransform) : Matrix(),
133 aSamplingFilter),
134 aOptions);
135 }
136
FillRectWithMask(DrawTarget * aDT,const gfx::Point & aDeviceOffset,const Rect & aRect,SourceSurface * aSurface,SamplingFilter aSamplingFilter,const DrawOptions & aOptions,Layer * aMaskLayer)137 void FillRectWithMask(DrawTarget* aDT, const gfx::Point& aDeviceOffset,
138 const Rect& aRect, SourceSurface* aSurface,
139 SamplingFilter aSamplingFilter,
140 const DrawOptions& aOptions, Layer* aMaskLayer) {
141 AutoMoz2DMaskData mask;
142 if (GetMaskData(aMaskLayer, aDeviceOffset, &mask)) {
143 const Matrix& maskTransform = mask.GetTransform();
144 FillRectWithMask(aDT, aRect, aSurface, aSamplingFilter, aOptions,
145 ExtendMode::CLAMP, mask.GetSurface(), &maskTransform);
146 return;
147 }
148
149 FillRectWithMask(aDT, aRect, aSurface, aSamplingFilter, aOptions,
150 ExtendMode::CLAMP);
151 }
152
FillPathWithMask(DrawTarget * aDT,const Path * aPath,const Rect & aClipRect,const DeviceColor & aColor,const DrawOptions & aOptions,SourceSurface * aMaskSource,const Matrix * aMaskTransform)153 void FillPathWithMask(DrawTarget* aDT, const Path* aPath, const Rect& aClipRect,
154 const DeviceColor& aColor, const DrawOptions& aOptions,
155 SourceSurface* aMaskSource,
156 const Matrix* aMaskTransform) {
157 if (aMaskSource && aMaskTransform) {
158 aDT->PushClipRect(aClipRect);
159 Matrix oldTransform = aDT->GetTransform();
160
161 aDT->SetTransform(*aMaskTransform);
162 aDT->MaskSurface(ColorPattern(aColor), aMaskSource, Point(), aOptions);
163 aDT->SetTransform(oldTransform);
164 aDT->PopClip();
165 return;
166 }
167
168 aDT->Fill(aPath, ColorPattern(aColor), aOptions);
169 }
170
FillPathWithMask(DrawTarget * aDT,const Path * aPath,const Rect & aClipRect,SourceSurface * aSurface,SamplingFilter aSamplingFilter,const DrawOptions & aOptions,ExtendMode aExtendMode,SourceSurface * aMaskSource,const Matrix * aMaskTransform,const Matrix * aSurfaceTransform)171 void FillPathWithMask(DrawTarget* aDT, const Path* aPath, const Rect& aClipRect,
172 SourceSurface* aSurface, SamplingFilter aSamplingFilter,
173 const DrawOptions& aOptions, ExtendMode aExtendMode,
174 SourceSurface* aMaskSource, const Matrix* aMaskTransform,
175 const Matrix* aSurfaceTransform) {
176 if (aMaskSource && aMaskTransform) {
177 aDT->PushClipRect(aClipRect);
178 Matrix oldTransform = aDT->GetTransform();
179
180 Matrix inverseMask = *aMaskTransform;
181 inverseMask.Invert();
182
183 Matrix transform = oldTransform * inverseMask;
184 if (aSurfaceTransform) {
185 transform = (*aSurfaceTransform) * transform;
186 }
187
188 SurfacePattern source(aSurface, aExtendMode, transform, aSamplingFilter);
189
190 aDT->SetTransform(*aMaskTransform);
191 aDT->MaskSurface(source, aMaskSource, Point(0, 0), aOptions);
192 aDT->SetTransform(oldTransform);
193 aDT->PopClip();
194 return;
195 }
196
197 aDT->Fill(aPath,
198 SurfacePattern(aSurface, aExtendMode,
199 aSurfaceTransform ? (*aSurfaceTransform) : Matrix(),
200 aSamplingFilter),
201 aOptions);
202 }
203
ToData(Layer * aLayer)204 BasicImplData* ToData(Layer* aLayer) {
205 return static_cast<BasicImplData*>(aLayer->ImplData());
206 }
207
GetEffectiveOperator(Layer * aLayer)208 gfx::CompositionOp GetEffectiveOperator(Layer* aLayer) {
209 CompositionOp op = aLayer->GetEffectiveMixBlendMode();
210
211 if (op != CompositionOp::OP_OVER) {
212 return op;
213 }
214
215 return ToData(aLayer)->GetOperator();
216 }
217
218 } // namespace layers
219 } // namespace mozilla
220