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