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 "DrawTargetOffset.h"
8 #include "Logging.h"
9 #include "PathHelpers.h"
10 
11 namespace mozilla {
12 namespace gfx {
13 
14 DrawTargetOffset::DrawTargetOffset() = default;
15 
Init(DrawTarget * aDrawTarget,IntPoint aOrigin)16 bool DrawTargetOffset::Init(DrawTarget* aDrawTarget, IntPoint aOrigin) {
17   mDrawTarget = aDrawTarget;
18   mOrigin = aOrigin;
19   mDrawTarget->SetTransform(Matrix::Translation(-mOrigin.x, -mOrigin.y));
20   mFormat = mDrawTarget->GetFormat();
21   SetPermitSubpixelAA(IsOpaque(mFormat));
22   return true;
23 }
24 
Snapshot()25 already_AddRefed<SourceSurface> DrawTargetOffset::Snapshot() {
26   RefPtr<SourceSurface> snapshot = mDrawTarget->Snapshot();
27 
28   if (!snapshot) {
29     return nullptr;
30   }
31 
32   return MakeAndAddRef<SourceSurfaceOffset>(snapshot, mOrigin);
33 }
34 
DetachAllSnapshots()35 void DrawTargetOffset::DetachAllSnapshots() {}
36 
37 // Skip the mClippedOut check since this is only used for Flush() which
38 // should happen even if we're clipped.
39 #define OFFSET_COMMAND(command) \
40   void DrawTargetOffset::command() { mDrawTarget->command(); }
41 #define OFFSET_COMMAND1(command, type1) \
42   void DrawTargetOffset::command(type1 arg1) { mDrawTarget->command(arg1); }
43 #define OFFSET_COMMAND3(command, type1, type2, type3)                  \
44   void DrawTargetOffset::command(type1 arg1, type2 arg2, type3 arg3) { \
45     mDrawTarget->command(arg1, arg2, arg3);                            \
46   }
47 #define OFFSET_COMMAND4(command, type1, type2, type3, type4)         \
48   void DrawTargetOffset::command(type1 arg1, type2 arg2, type3 arg3, \
49                                  type4 arg4) {                       \
50     mDrawTarget->command(arg1, arg2, arg3, arg4);                    \
51   }
52 #define OFFSET_COMMAND5(command, type1, type2, type3, type4, type5)  \
53   void DrawTargetOffset::command(type1 arg1, type2 arg2, type3 arg3, \
54                                  type4 arg4, type5 arg5) {           \
55     mDrawTarget->command(arg1, arg2, arg3, arg4, arg5);              \
56   }
57 
58 OFFSET_COMMAND(Flush)
OFFSET_COMMAND1(ClearRect,const Rect &)59 OFFSET_COMMAND1(ClearRect, const Rect&)
60 OFFSET_COMMAND4(MaskSurface, const Pattern&, SourceSurface*, Point,
61                 const DrawOptions&)
62 OFFSET_COMMAND4(FillGlyphs, ScaledFont*, const GlyphBuffer&, const Pattern&,
63                 const DrawOptions&)
64 OFFSET_COMMAND5(StrokeGlyphs, ScaledFont*, const GlyphBuffer&, const Pattern&,
65                 const StrokeOptions&, const DrawOptions&)
66 OFFSET_COMMAND3(FillRoundedRect, const RoundedRect&, const Pattern&,
67                 const DrawOptions&)
68 
69 bool DrawTargetOffset::Draw3DTransformedSurface(SourceSurface* aSrc,
70                                                 const Matrix4x4& aMatrix) {
71   return mDrawTarget->Draw3DTransformedSurface(aSrc, aMatrix);
72 }
73 
OFFSET_COMMAND3(Mask,const Pattern &,const Pattern &,const DrawOptions &)74 OFFSET_COMMAND3(Mask, const Pattern&, const Pattern&, const DrawOptions&)
75 
76 void DrawTargetOffset::DrawFilter(FilterNode* aNode, const Rect& aSourceRect,
77                                   const Point& aDestPoint,
78                                   const DrawOptions& aOptions) {
79   auto clone = mTransform;
80   bool invertible = clone.Invert();
81   // aSourceRect is in filter space. The filter outputs from aSourceRect need
82   // to be drawn at aDestPoint in user space.
83   Rect userSpaceSource = Rect(aDestPoint, aSourceRect.Size());
84   if (invertible) {
85     // Try to reduce the source rect so that it's not much bigger
86     // than the draw target. The result is not minimal. Examples
87     // are left as an exercise for the reader.
88     auto destRect = Rect(mDrawTarget->GetRect() + mOrigin);
89     Rect userSpaceBounds = clone.TransformBounds(destRect);
90     userSpaceSource = userSpaceSource.Intersect(userSpaceBounds);
91   }
92 
93   // Compute how much we moved the top-left of the source rect by, and use that
94   // to compute the new dest point, and move our intersected source rect back
95   // into the (new) filter space.
96   Point shift = userSpaceSource.TopLeft() - aDestPoint;
97   Rect filterSpaceSource =
98       Rect(aSourceRect.TopLeft() + shift, userSpaceSource.Size());
99   mDrawTarget->DrawFilter(aNode, filterSpaceSource, aDestPoint + shift,
100                           aOptions);
101 }
102 
PushClip(const Path * aPath)103 void DrawTargetOffset::PushClip(const Path* aPath) {
104   mDrawTarget->PushClip(aPath);
105 }
106 
PushClipRect(const Rect & aRect)107 void DrawTargetOffset::PushClipRect(const Rect& aRect) {
108   mDrawTarget->PushClipRect(aRect);
109 }
110 
PopClip()111 void DrawTargetOffset::PopClip() { mDrawTarget->PopClip(); }
112 
CopySurface(SourceSurface * aSurface,const IntRect & aSourceRect,const IntPoint & aDestination)113 void DrawTargetOffset::CopySurface(SourceSurface* aSurface,
114                                    const IntRect& aSourceRect,
115                                    const IntPoint& aDestination) {
116   IntPoint tileOrigin = mOrigin;
117   // CopySurface ignores the transform, account for that here.
118   mDrawTarget->CopySurface(aSurface, aSourceRect, aDestination - tileOrigin);
119 }
120 
SetTransform(const Matrix & aTransform)121 void DrawTargetOffset::SetTransform(const Matrix& aTransform) {
122   Matrix mat = aTransform;
123   mat.PostTranslate(Float(-mOrigin.x), Float(-mOrigin.y));
124   mDrawTarget->SetTransform(mat);
125 
126   DrawTarget::SetTransform(aTransform);
127 }
128 
SetPermitSubpixelAA(bool aPermitSubpixelAA)129 void DrawTargetOffset::SetPermitSubpixelAA(bool aPermitSubpixelAA) {
130   mDrawTarget->SetPermitSubpixelAA(aPermitSubpixelAA);
131 }
132 
DrawSurface(SourceSurface * aSurface,const Rect & aDest,const Rect & aSource,const DrawSurfaceOptions & aSurfaceOptions,const DrawOptions & aDrawOptions)133 void DrawTargetOffset::DrawSurface(SourceSurface* aSurface, const Rect& aDest,
134                                    const Rect& aSource,
135                                    const DrawSurfaceOptions& aSurfaceOptions,
136                                    const DrawOptions& aDrawOptions) {
137   mDrawTarget->DrawSurface(aSurface, aDest, aSource, aSurfaceOptions,
138                            aDrawOptions);
139 }
140 
FillRect(const Rect & aRect,const Pattern & aPattern,const DrawOptions & aDrawOptions)141 void DrawTargetOffset::FillRect(const Rect& aRect, const Pattern& aPattern,
142                                 const DrawOptions& aDrawOptions) {
143   mDrawTarget->FillRect(aRect, aPattern, aDrawOptions);
144 }
145 
Stroke(const Path * aPath,const Pattern & aPattern,const StrokeOptions & aStrokeOptions,const DrawOptions & aDrawOptions)146 void DrawTargetOffset::Stroke(const Path* aPath, const Pattern& aPattern,
147                               const StrokeOptions& aStrokeOptions,
148                               const DrawOptions& aDrawOptions) {
149   mDrawTarget->Stroke(aPath, aPattern, aStrokeOptions, aDrawOptions);
150 }
151 
StrokeRect(const Rect & aRect,const Pattern & aPattern,const StrokeOptions & aStrokeOptions,const DrawOptions & aDrawOptions)152 void DrawTargetOffset::StrokeRect(const Rect& aRect, const Pattern& aPattern,
153                                   const StrokeOptions& aStrokeOptions,
154                                   const DrawOptions& aDrawOptions) {
155   mDrawTarget->StrokeRect(aRect, aPattern, aStrokeOptions, aDrawOptions);
156 }
157 
StrokeLine(const Point & aStart,const Point & aEnd,const Pattern & aPattern,const StrokeOptions & aStrokeOptions,const DrawOptions & aDrawOptions)158 void DrawTargetOffset::StrokeLine(const Point& aStart, const Point& aEnd,
159                                   const Pattern& aPattern,
160                                   const StrokeOptions& aStrokeOptions,
161                                   const DrawOptions& aDrawOptions) {
162   mDrawTarget->StrokeLine(aStart, aEnd, aPattern, aStrokeOptions, aDrawOptions);
163 }
164 
Fill(const Path * aPath,const Pattern & aPattern,const DrawOptions & aDrawOptions)165 void DrawTargetOffset::Fill(const Path* aPath, const Pattern& aPattern,
166                             const DrawOptions& aDrawOptions) {
167   mDrawTarget->Fill(aPath, aPattern, aDrawOptions);
168 }
169 
PushLayer(bool aOpaque,Float aOpacity,SourceSurface * aMask,const Matrix & aMaskTransform,const IntRect & aBounds,bool aCopyBackground)170 void DrawTargetOffset::PushLayer(bool aOpaque, Float aOpacity,
171                                  SourceSurface* aMask,
172                                  const Matrix& aMaskTransform,
173                                  const IntRect& aBounds, bool aCopyBackground) {
174   IntRect bounds = aBounds - mOrigin;
175 
176   mDrawTarget->PushLayer(aOpaque, aOpacity, aMask, aMaskTransform, bounds,
177                          aCopyBackground);
178   SetPermitSubpixelAA(mDrawTarget->GetPermitSubpixelAA());
179 }
180 
IntoLuminanceSource(LuminanceType aLuminanceType,float aOpacity)181 already_AddRefed<SourceSurface> DrawTargetOffset::IntoLuminanceSource(
182     LuminanceType aLuminanceType, float aOpacity) {
183   RefPtr<SourceSurface> surface =
184       mDrawTarget->IntoLuminanceSource(aLuminanceType, aOpacity);
185 
186   if (!surface) {
187     return nullptr;
188   }
189 
190   return MakeAndAddRef<SourceSurfaceOffset>(surface, mOrigin);
191 }
192 
PushLayerWithBlend(bool aOpaque,Float aOpacity,SourceSurface * aMask,const Matrix & aMaskTransform,const IntRect & aBounds,bool aCopyBackground,CompositionOp aOp)193 void DrawTargetOffset::PushLayerWithBlend(bool aOpaque, Float aOpacity,
194                                           SourceSurface* aMask,
195                                           const Matrix& aMaskTransform,
196                                           const IntRect& aBounds,
197                                           bool aCopyBackground,
198                                           CompositionOp aOp) {
199   IntRect bounds = aBounds - mOrigin;
200 
201   mDrawTarget->PushLayerWithBlend(aOpaque, aOpacity, aMask, aMaskTransform,
202                                   bounds, aCopyBackground, aOp);
203   SetPermitSubpixelAA(mDrawTarget->GetPermitSubpixelAA());
204 }
205 
PopLayer()206 void DrawTargetOffset::PopLayer() {
207   mDrawTarget->PopLayer();
208   SetPermitSubpixelAA(mDrawTarget->GetPermitSubpixelAA());
209 }
210 
211 }  // namespace gfx
212 }  // namespace mozilla
213