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