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 Color & aColor,const DrawOptions & aOptions,SourceSurface * aMaskSource,const Matrix * aMaskTransform)71 void FillRectWithMask(DrawTarget* aDT, const Rect& aRect, const Color& aColor,
72                       const DrawOptions& aOptions, SourceSurface* aMaskSource,
73                       const Matrix* aMaskTransform) {
74   if (aMaskSource && aMaskTransform) {
75     aDT->PushClipRect(aRect);
76     Matrix oldTransform = aDT->GetTransform();
77 
78     aDT->SetTransform(*aMaskTransform);
79     aDT->MaskSurface(ColorPattern(aColor), aMaskSource, Point(), aOptions);
80     aDT->SetTransform(oldTransform);
81     aDT->PopClip();
82     return;
83   }
84 
85   aDT->FillRect(aRect, ColorPattern(aColor), aOptions);
86 }
FillRectWithMask(DrawTarget * aDT,const gfx::Point & aDeviceOffset,const Rect & aRect,const Color & aColor,const DrawOptions & aOptions,Layer * aMaskLayer)87 void FillRectWithMask(DrawTarget* aDT, const gfx::Point& aDeviceOffset,
88                       const Rect& aRect, const Color& aColor,
89                       const DrawOptions& aOptions, Layer* aMaskLayer) {
90   AutoMoz2DMaskData mask;
91   if (GetMaskData(aMaskLayer, aDeviceOffset, &mask)) {
92     const Matrix& maskTransform = mask.GetTransform();
93     FillRectWithMask(aDT, aRect, aColor, aOptions, mask.GetSurface(),
94                      &maskTransform);
95     return;
96   }
97 
98   FillRectWithMask(aDT, aRect, aColor, aOptions);
99 }
100 
FillRectWithMask(DrawTarget * aDT,const Rect & aRect,SourceSurface * aSurface,SamplingFilter aSamplingFilter,const DrawOptions & aOptions,ExtendMode aExtendMode,SourceSurface * aMaskSource,const Matrix * aMaskTransform,const Matrix * aSurfaceTransform)101 void FillRectWithMask(DrawTarget* aDT, const Rect& aRect,
102                       SourceSurface* aSurface, SamplingFilter aSamplingFilter,
103                       const DrawOptions& aOptions, ExtendMode aExtendMode,
104                       SourceSurface* aMaskSource, const Matrix* aMaskTransform,
105                       const Matrix* aSurfaceTransform) {
106   if (aMaskSource && aMaskTransform) {
107     aDT->PushClipRect(aRect);
108     Matrix oldTransform = aDT->GetTransform();
109 
110     Matrix inverseMask = *aMaskTransform;
111     inverseMask.Invert();
112 
113     Matrix transform = oldTransform * inverseMask;
114     if (aSurfaceTransform) {
115       transform = (*aSurfaceTransform) * transform;
116     }
117 
118     SurfacePattern source(aSurface, aExtendMode, transform, aSamplingFilter);
119 
120     aDT->SetTransform(*aMaskTransform);
121     aDT->MaskSurface(source, aMaskSource, Point(0, 0), aOptions);
122 
123     aDT->SetTransform(oldTransform);
124     aDT->PopClip();
125     return;
126   }
127 
128   aDT->FillRect(
129       aRect,
130       SurfacePattern(aSurface, aExtendMode,
131                      aSurfaceTransform ? (*aSurfaceTransform) : Matrix(),
132                      aSamplingFilter),
133       aOptions);
134 }
135 
FillRectWithMask(DrawTarget * aDT,const gfx::Point & aDeviceOffset,const Rect & aRect,SourceSurface * aSurface,SamplingFilter aSamplingFilter,const DrawOptions & aOptions,Layer * aMaskLayer)136 void FillRectWithMask(DrawTarget* aDT, const gfx::Point& aDeviceOffset,
137                       const Rect& aRect, SourceSurface* aSurface,
138                       SamplingFilter aSamplingFilter,
139                       const DrawOptions& aOptions, Layer* aMaskLayer) {
140   AutoMoz2DMaskData mask;
141   if (GetMaskData(aMaskLayer, aDeviceOffset, &mask)) {
142     const Matrix& maskTransform = mask.GetTransform();
143     FillRectWithMask(aDT, aRect, aSurface, aSamplingFilter, aOptions,
144                      ExtendMode::CLAMP, mask.GetSurface(), &maskTransform);
145     return;
146   }
147 
148   FillRectWithMask(aDT, aRect, aSurface, aSamplingFilter, aOptions,
149                    ExtendMode::CLAMP);
150 }
151 
FillPathWithMask(DrawTarget * aDT,const Path * aPath,const Rect & aClipRect,const Color & aColor,const DrawOptions & aOptions,SourceSurface * aMaskSource,const Matrix * aMaskTransform)152 void FillPathWithMask(DrawTarget* aDT, const Path* aPath, const Rect& aClipRect,
153                       const Color& aColor, const DrawOptions& aOptions,
154                       SourceSurface* aMaskSource,
155                       const Matrix* aMaskTransform) {
156   if (aMaskSource && aMaskTransform) {
157     aDT->PushClipRect(aClipRect);
158     Matrix oldTransform = aDT->GetTransform();
159 
160     aDT->SetTransform(*aMaskTransform);
161     aDT->MaskSurface(ColorPattern(aColor), aMaskSource, Point(), aOptions);
162     aDT->SetTransform(oldTransform);
163     aDT->PopClip();
164     return;
165   }
166 
167   aDT->Fill(aPath, ColorPattern(aColor), aOptions);
168 }
169 
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)170 void FillPathWithMask(DrawTarget* aDT, const Path* aPath, const Rect& aClipRect,
171                       SourceSurface* aSurface, SamplingFilter aSamplingFilter,
172                       const DrawOptions& aOptions, ExtendMode aExtendMode,
173                       SourceSurface* aMaskSource, const Matrix* aMaskTransform,
174                       const Matrix* aSurfaceTransform) {
175   if (aMaskSource && aMaskTransform) {
176     aDT->PushClipRect(aClipRect);
177     Matrix oldTransform = aDT->GetTransform();
178 
179     Matrix inverseMask = *aMaskTransform;
180     inverseMask.Invert();
181 
182     Matrix transform = oldTransform * inverseMask;
183     if (aSurfaceTransform) {
184       transform = (*aSurfaceTransform) * transform;
185     }
186 
187     SurfacePattern source(aSurface, aExtendMode, transform, aSamplingFilter);
188 
189     aDT->SetTransform(*aMaskTransform);
190     aDT->MaskSurface(source, aMaskSource, Point(0, 0), aOptions);
191     aDT->SetTransform(oldTransform);
192     aDT->PopClip();
193     return;
194   }
195 
196   aDT->Fill(aPath,
197             SurfacePattern(aSurface, aExtendMode,
198                            aSurfaceTransform ? (*aSurfaceTransform) : Matrix(),
199                            aSamplingFilter),
200             aOptions);
201 }
202 
ToData(Layer * aLayer)203 BasicImplData* ToData(Layer* aLayer) {
204   return static_cast<BasicImplData*>(aLayer->ImplData());
205 }
206 
GetEffectiveOperator(Layer * aLayer)207 gfx::CompositionOp GetEffectiveOperator(Layer* aLayer) {
208   CompositionOp op = aLayer->GetEffectiveMixBlendMode();
209 
210   if (op != CompositionOp::OP_OVER) {
211     return op;
212   }
213 
214   return ToData(aLayer)->GetOperator();
215 }
216 
ToShadowable(Layer * aLayer)217 ShadowableLayer* ToShadowable(Layer* aLayer) {
218   return aLayer->AsShadowableLayer();
219 }
220 
ShouldShadow(Layer * aLayer)221 bool ShouldShadow(Layer* aLayer) {
222   if (!ToShadowable(aLayer)) {
223     MOZ_ASSERT(aLayer->GetType() == Layer::TYPE_READBACK,
224                "Only expect not to shadow ReadbackLayers");
225     return false;
226   }
227   return true;
228 }
229 
230 }  // namespace layers
231 }  // namespace mozilla
232