1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
|
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BaseRenderingContext2D_h
#define BaseRenderingContext2D_h
#include "bindings/core/v8/UnionTypesCore.h"
#include "bindings/modules/v8/UnionTypesModules.h"
#include "modules/ModulesExport.h"
#include "modules/canvas2d/CanvasGradient.h"
#include "modules/canvas2d/CanvasPathMethods.h"
#include "modules/canvas2d/CanvasRenderingContext2DState.h"
#include "modules/canvas2d/CanvasStyle.h"
#include "third_party/skia/include/core/SkCanvas.h"
namespace blink {
class CanvasImageSource;
class Color;
class Image;
class ImageBuffer;
class Path2D;
class SVGMatrixTearOff;
typedef HTMLImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmap CanvasImageSourceUnion;
class MODULES_EXPORT BaseRenderingContext2D : public WillBeGarbageCollectedMixin, public CanvasPathMethods {
WTF_MAKE_NONCOPYABLE(BaseRenderingContext2D);
public:
~BaseRenderingContext2D() override;
void strokeStyle(StringOrCanvasGradientOrCanvasPattern&) const;
void setStrokeStyle(const StringOrCanvasGradientOrCanvasPattern&);
void fillStyle(StringOrCanvasGradientOrCanvasPattern&) const;
void setFillStyle(const StringOrCanvasGradientOrCanvasPattern&);
double lineWidth() const;
void setLineWidth(double);
String lineCap() const;
void setLineCap(const String&);
String lineJoin() const;
void setLineJoin(const String&);
double miterLimit() const;
void setMiterLimit(double);
const Vector<double>& getLineDash() const;
void setLineDash(const Vector<double>&);
double lineDashOffset() const;
void setLineDashOffset(double);
double shadowOffsetX() const;
void setShadowOffsetX(double);
double shadowOffsetY() const;
void setShadowOffsetY(double);
double shadowBlur() const;
void setShadowBlur(double);
String shadowColor() const;
void setShadowColor(const String&);
double globalAlpha() const;
void setGlobalAlpha(double);
String globalCompositeOperation() const;
void setGlobalCompositeOperation(const String&);
String filter() const;
void setFilter(const String&);
void save();
void restore();
PassRefPtrWillBeRawPtr<SVGMatrixTearOff> currentTransform() const;
void setCurrentTransform(PassRefPtrWillBeRawPtr<SVGMatrixTearOff>);
void scale(double sx, double sy);
void rotate(double angleInRadians);
void translate(double tx, double ty);
void transform(double m11, double m12, double m21, double m22, double dx, double dy);
void setTransform(double m11, double m12, double m21, double m22, double dx, double dy);
void resetTransform();
void beginPath();
void fill(const String& winding = "nonzero");
void fill(Path2D*, const String& winding = "nonzero");
void stroke();
void stroke(Path2D*);
void clip(const String& winding = "nonzero");
void clip(Path2D*, const String& winding = "nonzero");
bool isPointInPath(const double x, const double y, const String& winding = "nonzero");
bool isPointInPath(Path2D*, const double x, const double y, const String& winding = "nonzero");
bool isPointInStroke(const double x, const double y);
bool isPointInStroke(Path2D*, const double x, const double y);
void clearRect(double x, double y, double width, double height);
void fillRect(double x, double y, double width, double height);
void strokeRect(double x, double y, double width, double height);
void drawImage(const CanvasImageSourceUnion&, double x, double y, ExceptionState&);
void drawImage(const CanvasImageSourceUnion&, double x, double y, double width, double height, ExceptionState&);
void drawImage(const CanvasImageSourceUnion&, double sx, double sy, double sw, double sh, double dx, double dy, double dw, double dh, ExceptionState&);
void drawImage(CanvasImageSource*, double sx, double sy, double sw, double sh, double dx, double dy, double dw, double dh, ExceptionState&);
CanvasGradient* createLinearGradient(double x0, double y0, double x1, double y1);
CanvasGradient* createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1, ExceptionState&);
CanvasPattern* createPattern(const CanvasImageSourceUnion&, const String& repetitionType, ExceptionState&);
ImageData* createImageData(ImageData*, ExceptionState&) const;
ImageData* createImageData(double width, double height, ExceptionState&) const;
ImageData* getImageData(double sx, double sy, double sw, double sh, ExceptionState&) const;
void putImageData(ImageData*, double dx, double dy, ExceptionState&);
void putImageData(ImageData*, double dx, double dy, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight, ExceptionState&);
bool imageSmoothingEnabled() const;
void setImageSmoothingEnabled(bool);
String imageSmoothingQuality() const;
void setImageSmoothingQuality(const String&);
virtual bool originClean() const = 0;
virtual void setOriginTainted() = 0;
virtual bool wouldTaintOrigin(CanvasImageSource*) = 0;
virtual int width() const = 0;
virtual int height() const = 0;
virtual bool hasImageBuffer() const = 0;
virtual ImageBuffer* imageBuffer() const = 0;
virtual bool parseColorOrCurrentColor(Color&, const String& colorString) const = 0;
virtual SkCanvas* drawingCanvas() const = 0;
virtual SkCanvas* existingDrawingCanvas() const = 0;
virtual void disableDeferral(DisableDeferralReason) = 0;
virtual AffineTransform baseTransform() const = 0;
virtual void didDraw(const SkIRect& dirtyRect) = 0;
virtual bool stateHasFilter() = 0;
virtual SkImageFilter* stateGetFilter() = 0;
virtual void validateStateStack() = 0;
virtual bool hasAlpha() const = 0;
virtual bool isContextLost() const = 0;
DECLARE_VIRTUAL_TRACE();
protected:
BaseRenderingContext2D();
CanvasRenderingContext2DState& modifiableState();
const CanvasRenderingContext2DState& state() const { return *m_stateStack.last(); }
bool computeDirtyRect(const FloatRect& localBounds, SkIRect*);
bool computeDirtyRect(const FloatRect& localBounds, const SkIRect& transformedClipBounds, SkIRect*);
template<typename DrawFunc, typename ContainsFunc>
bool draw(const DrawFunc&, const ContainsFunc&, const SkRect& bounds, CanvasRenderingContext2DState::PaintType, CanvasRenderingContext2DState::ImageType = CanvasRenderingContext2DState::NoImage);
void inflateStrokeRect(FloatRect&) const;
enum DrawType {
ClipFill, // Fill that is already known to cover the current clip
UntransformedUnclippedFill
};
void checkOverdraw(const SkRect&, const SkPaint*, CanvasRenderingContext2DState::ImageType, DrawType);
WillBeHeapVector<OwnPtrWillBeMember<CanvasRenderingContext2DState>> m_stateStack;
AntiAliasingMode m_clipAntialiasing;
private:
void realizeSaves();
bool shouldDrawImageAntialiased(const FloatRect& destRect) const;
void drawPathInternal(const Path&, CanvasRenderingContext2DState::PaintType, SkPath::FillType = SkPath::kWinding_FillType);
void drawImageInternal(SkCanvas*, CanvasImageSource*, Image*, const FloatRect& srcRect, const FloatRect& dstRect, const SkPaint*);
void clipInternal(const Path&, const String& windingRuleString);
bool isPointInPathInternal(const Path&, const double x, const double y, const String& windingRuleString);
bool isPointInStrokeInternal(const Path&, const double x, const double y);
static bool isFullCanvasCompositeMode(SkXfermode::Mode);
template<typename DrawFunc>
void compositedDraw(const DrawFunc&, SkCanvas*, CanvasRenderingContext2DState::PaintType, CanvasRenderingContext2DState::ImageType);
void clearCanvas();
bool rectContainsTransformedRect(const FloatRect&, const SkIRect&) const;
};
template<typename DrawFunc, typename ContainsFunc>
bool BaseRenderingContext2D::draw(const DrawFunc& drawFunc, const ContainsFunc& drawCoversClipBounds, const SkRect& bounds, CanvasRenderingContext2DState::PaintType paintType, CanvasRenderingContext2DState::ImageType imageType)
{
if (!state().isTransformInvertible())
return false;
SkIRect clipBounds;
if (!drawingCanvas() || !drawingCanvas()->getClipDeviceBounds(&clipBounds))
return false;
// If gradient size is zero, then paint nothing.
CanvasStyle* style = state().style(paintType);
if (style) {
CanvasGradient* gradient = style->getCanvasGradient();
if (gradient && gradient->getGradient()->isZeroSize())
return false;
}
if (isFullCanvasCompositeMode(state().globalComposite()) || stateHasFilter()) {
compositedDraw(drawFunc, drawingCanvas(), paintType, imageType);
didDraw(clipBounds);
} else if (state().globalComposite() == SkXfermode::kSrc_Mode) {
clearCanvas(); // takes care of checkOverdraw()
const SkPaint* paint = state().getPaint(paintType, DrawForegroundOnly, imageType);
drawFunc(drawingCanvas(), paint);
didDraw(clipBounds);
} else {
SkIRect dirtyRect;
if (computeDirtyRect(bounds, clipBounds, &dirtyRect)) {
const SkPaint* paint = state().getPaint(paintType, DrawShadowAndForeground, imageType);
if (paintType != CanvasRenderingContext2DState::StrokePaintType && drawCoversClipBounds(clipBounds))
checkOverdraw(bounds, paint, imageType, ClipFill);
drawFunc(drawingCanvas(), paint);
didDraw(dirtyRect);
}
}
return true;
}
template<typename DrawFunc>
void BaseRenderingContext2D::compositedDraw(const DrawFunc& drawFunc, SkCanvas* c, CanvasRenderingContext2DState::PaintType paintType, CanvasRenderingContext2DState::ImageType imageType)
{
SkImageFilter* filter = stateGetFilter();
ASSERT(isFullCanvasCompositeMode(state().globalComposite()) || filter);
SkMatrix ctm = c->getTotalMatrix();
c->resetMatrix();
SkPaint compositePaint;
compositePaint.setXfermodeMode(state().globalComposite());
if (state().shouldDrawShadows()) {
// unroll into two independently composited passes if drawing shadows
SkPaint shadowPaint = *state().getPaint(paintType, DrawShadowOnly, imageType);
int saveCount = c->getSaveCount();
if (filter) {
SkPaint filterPaint;
filterPaint.setImageFilter(filter);
// TODO(junov): crbug.com/502921 We could use primitive bounds if we knew that the filter
// does not affect transparent black regions.
c->saveLayer(nullptr, &shadowPaint);
c->saveLayer(nullptr, &filterPaint);
SkPaint foregroundPaint = *state().getPaint(paintType, DrawForegroundOnly, imageType);
c->setMatrix(ctm);
drawFunc(c, &foregroundPaint);
} else {
ASSERT(isFullCanvasCompositeMode(state().globalComposite()));
c->saveLayer(nullptr, &compositePaint);
shadowPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
c->setMatrix(ctm);
drawFunc(c, &shadowPaint);
}
c->restoreToCount(saveCount);
}
compositePaint.setImageFilter(filter);
// TODO(junov): crbug.com/502921 We could use primitive bounds if we knew that the filter
// does not affect transparent black regions *and* !isFullCanvasCompositeMode
c->saveLayer(nullptr, &compositePaint);
SkPaint foregroundPaint = *state().getPaint(paintType, DrawForegroundOnly, imageType);
foregroundPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
c->setMatrix(ctm);
drawFunc(c, &foregroundPaint);
c->restore();
c->setMatrix(ctm);
}
} // namespace blink
#endif // BaseRenderingContext2D_h
|