blob: c7e1d6e8987795f4f230db032629e6825ddad157 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060023#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080024#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000025#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050026#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070027#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070028#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070029#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000030#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070031#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000032#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050033#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070035#include "SkShadowPaintFilterCanvas.h"
36#include "SkShadowShader.h"
robertphillips4418dba2016-03-07 12:45:14 -080037#include "SkSpecialImage.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040038#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000039#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070040#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000041#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000042#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080043#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070044#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000045
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000046#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080047#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#include "GrRenderTarget.h"
Brian Osman3b655982017-03-07 16:58:08 -050049#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070050
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050052#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050053#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000054
reede3b38ce2016-01-08 09:18:44 -080055#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
56
Mike Reed139e5e02017-03-08 11:29:33 -050057class SkNoPixelsDevice : public SkBaseDevice {
58public:
59 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props)
60 : SkBaseDevice(SkImageInfo::MakeUnknown(bounds.width(), bounds.height()), props)
Mike Reed566e53c2017-03-10 10:49:45 -050061 {
Mike Reede393a622017-03-10 16:35:25 -050062 // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage
63 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed566e53c2017-03-10 10:49:45 -050064 }
Mike Reed139e5e02017-03-08 11:29:33 -050065
66 void resetForNextPicture(const SkIRect& bounds) {
Mike Reede393a622017-03-10 16:35:25 -050067 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
Mike Reed139e5e02017-03-08 11:29:33 -050068 this->privateResize(bounds.width(), bounds.height());
69 }
70
71protected:
72 // We don't track the clip at all (for performance), but we have to respond to some queries.
73 // We pretend to be wide-open. We could pretend to always be empty, but that *seems* worse.
74 void onSave() override {}
75 void onRestore() override {}
76 void onClipRect(const SkRect& rect, SkClipOp, bool aa) override {}
77 void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override {}
78 void onClipPath(const SkPath& path, SkClipOp, bool aa) override {}
79 void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {}
80 void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override {}
81 bool onClipIsAA() const override { return false; }
82 void onAsRgnClip(SkRegion* rgn) const override {
83 rgn->setRect(SkIRect::MakeWH(this->width(), this->height()));
84 }
85 ClipType onGetClipType() const override {
86 return kRect_ClipType;
87 }
88
89 void drawPaint(const SkPaint& paint) override {}
90 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
91 void drawRect(const SkRect&, const SkPaint&) override {}
92 void drawOval(const SkRect&, const SkPaint&) override {}
93 void drawRRect(const SkRRect&, const SkPaint&) override {}
94 void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override {}
95 void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {}
96 void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {}
97 void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&,
98 SkCanvas::SrcRectConstraint) override {}
99 void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {}
100 void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&,
101 const SkPaint&) override {}
102 void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override {}
Mike Reed2f6b5a42017-03-19 15:04:17 -0400103 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}
Mike Reed139e5e02017-03-08 11:29:33 -0500104
105private:
106 typedef SkBaseDevice INHERITED;
107};
108
109///////////////////////////////////////////////////////////////////////////////////////////////////
110
reedc83a2972015-07-16 07:40:45 -0700111/*
112 * Return true if the drawing this rect would hit every pixels in the canvas.
113 *
114 * Returns false if
115 * - rect does not contain the canvas' bounds
116 * - paint is not fill
117 * - paint would blur or otherwise change the coverage of the rect
118 */
119bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
120 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -0700121 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
122 (int)kNone_ShaderOverrideOpacity,
123 "need_matching_enums0");
124 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
125 (int)kOpaque_ShaderOverrideOpacity,
126 "need_matching_enums1");
127 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
128 (int)kNotOpaque_ShaderOverrideOpacity,
129 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -0700130
131 const SkISize size = this->getBaseLayerSize();
132 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500133
134 // if we're clipped at all, we can't overwrite the entire surface
135 {
136 SkBaseDevice* base = this->getDevice();
137 SkBaseDevice* top = this->getTopDevice();
138 if (base != top) {
139 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
140 }
141 if (!base->clipIsWideOpen()) {
142 return false;
143 }
reedc83a2972015-07-16 07:40:45 -0700144 }
145
146 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700147 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700148 return false; // conservative
149 }
halcanaryc5769b22016-08-10 07:13:21 -0700150
151 SkRect devRect;
152 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
153 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700154 return false;
155 }
156 }
157
158 if (paint) {
159 SkPaint::Style paintStyle = paint->getStyle();
160 if (!(paintStyle == SkPaint::kFill_Style ||
161 paintStyle == SkPaint::kStrokeAndFill_Style)) {
162 return false;
163 }
164 if (paint->getMaskFilter() || paint->getLooper()
165 || paint->getPathEffect() || paint->getImageFilter()) {
166 return false; // conservative
167 }
168 }
169 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
170}
171
172///////////////////////////////////////////////////////////////////////////////////////////////////
173
reedd990e2f2014-12-22 11:58:30 -0800174static bool gIgnoreSaveLayerBounds;
175void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
176 gIgnoreSaveLayerBounds = ignore;
177}
178bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
179 return gIgnoreSaveLayerBounds;
180}
181
reed0acf1b42014-12-22 16:12:38 -0800182static bool gTreatSpriteAsBitmap;
183void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
184 gTreatSpriteAsBitmap = spriteAsBitmap;
185}
186bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
187 return gTreatSpriteAsBitmap;
188}
189
reed@google.comda17f752012-08-16 18:27:05 +0000190// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191//#define SK_TRACE_SAVERESTORE
192
193#ifdef SK_TRACE_SAVERESTORE
194 static int gLayerCounter;
195 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
196 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
197
198 static int gRecCounter;
199 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
200 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
201
202 static int gCanvasCounter;
203 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
204 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
205#else
206 #define inc_layer()
207 #define dec_layer()
208 #define inc_rec()
209 #define dec_rec()
210 #define inc_canvas()
211 #define dec_canvas()
212#endif
213
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000214typedef SkTLazy<SkPaint> SkLazyPaint;
215
reedc83a2972015-07-16 07:40:45 -0700216void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000217 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700218 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
219 ? SkSurface::kDiscard_ContentChangeMode
220 : SkSurface::kRetain_ContentChangeMode);
221 }
222}
223
224void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
225 ShaderOverrideOpacity overrideOpacity) {
226 if (fSurfaceBase) {
227 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
228 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
229 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
230 // and therefore we don't care which mode we're in.
231 //
232 if (fSurfaceBase->outstandingImageSnapshot()) {
233 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
234 mode = SkSurface::kDiscard_ContentChangeMode;
235 }
236 }
237 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000238 }
239}
240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000243/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 The clip/matrix/proc are fields that reflect the top of the save/restore
245 stack. Whenever the canvas changes, it marks a dirty flag, and then before
246 these are used (assuming we're not on a layer) we rebuild these cache
247 values: they reflect the top of the save stack, but translated and clipped
248 by the device's XY offset and bitmap-bounds.
249*/
250struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400251 DeviceCM* fNext;
252 sk_sp<SkBaseDevice> fDevice;
253 SkRasterClip fClip;
254 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
255 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400256 sk_sp<SkImage> fClipImage;
257 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258
Florin Malita53f77bd2017-04-28 13:48:37 -0400259 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
260 sk_sp<SkImage> clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700261 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400262 , fDevice(std::move(device))
263 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700264 , fStashedMatrix(stashed)
Florin Malita53f77bd2017-04-28 13:48:37 -0400265 , fClipImage(std::move(clipImage))
266 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400267 {}
reed@google.com4b226022011-01-11 18:32:13 +0000268
mtkleinfeaadee2015-04-08 11:25:48 -0700269 void reset(const SkIRect& bounds) {
270 SkASSERT(!fPaint);
271 SkASSERT(!fNext);
272 SkASSERT(fDevice);
273 fClip.setRect(bounds);
274 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275};
276
277/* This is the record we keep for each save/restore level in the stack.
278 Since a level optionally copies the matrix and/or stack, we have pointers
279 for these fields. If the value is copied for this level, the copy is
280 stored in the ...Storage field, and the pointer points to that. If the
281 value is not copied for this level, we ignore ...Storage, and just point
282 at the corresponding value in the previous level in the stack.
283*/
284class SkCanvas::MCRec {
285public:
reed1f836ee2014-07-07 07:49:34 -0700286 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700287 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288 /* If there are any layers in the stack, this points to the top-most
289 one that is at or below this level in the stack (so we know what
290 bitmap/device to draw into from this level. This value is NOT
291 reference counted, since the real owner is either our fLayer field,
292 or a previous one in a lower level.)
293 */
Mike Reeda1361362017-03-07 09:37:29 -0500294 DeviceCM* fTopLayer;
295 SkConservativeClip fRasterClip;
296 SkMatrix fMatrix;
297 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298
vjiaoblacke5de1302016-07-13 14:05:28 -0700299 // This is the current cumulative depth (aggregate of all done translateZ calls)
300 SkScalar fCurDrawDepth;
301
Mike Reeda1361362017-03-07 09:37:29 -0500302 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700303 fFilter = nullptr;
304 fLayer = nullptr;
305 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800306 fMatrix.reset();
307 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700308 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700309
reedd9544982014-09-09 18:46:22 -0700310 // don't bother initializing fNext
311 inc_rec();
312 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700313 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
314 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700315 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700316 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700317 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800318 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700319
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320 // don't bother initializing fNext
321 inc_rec();
322 }
323 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000324 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700325 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000326 dec_rec();
327 }
mtkleinfeaadee2015-04-08 11:25:48 -0700328
329 void reset(const SkIRect& bounds) {
330 SkASSERT(fLayer);
331 SkASSERT(fDeferredSaveCount == 0);
332
333 fMatrix.reset();
334 fRasterClip.setRect(bounds);
335 fLayer->reset(bounds);
336 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337};
338
Mike Reeda1361362017-03-07 09:37:29 -0500339class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340public:
Mike Reeda1361362017-03-07 09:37:29 -0500341 SkDrawIter(SkCanvas* canvas)
342 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
343 {}
reed@google.com4b226022011-01-11 18:32:13 +0000344
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000346 const DeviceCM* rec = fCurrLayer;
347 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400348 fDevice = rec->fDevice.get();
349 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700351 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 return true;
353 }
354 return false;
355 }
reed@google.com4b226022011-01-11 18:32:13 +0000356
reed@google.com6f8f2922011-03-04 22:27:10 +0000357 int getX() const { return fDevice->getOrigin().x(); }
358 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000360
Mike Reed99330ba2017-02-22 11:01:08 -0500361 SkBaseDevice* fDevice;
362
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 const DeviceCM* fCurrLayer;
365 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366};
367
Florin Malita713b8ef2017-04-28 10:57:24 -0400368#define FOR_EACH_TOP_DEVICE( code ) \
369 do { \
370 DeviceCM* layer = fMCRec->fTopLayer; \
371 while (layer) { \
372 SkBaseDevice* device = layer->fDevice.get(); \
373 if (device) { \
374 code; \
375 } \
376 layer = layer->fNext; \
377 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500378 } while (0)
379
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380/////////////////////////////////////////////////////////////////////////////
381
reeddbc3cef2015-04-29 12:18:57 -0700382static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
383 return lazy->isValid() ? lazy->get() : lazy->set(orig);
384}
385
386/**
387 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700388 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700389 */
reedd053ce92016-03-22 10:17:23 -0700390static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700391 SkImageFilter* imgf = paint.getImageFilter();
392 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700393 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700394 }
395
reedd053ce92016-03-22 10:17:23 -0700396 SkColorFilter* imgCFPtr;
397 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700398 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700399 }
reedd053ce92016-03-22 10:17:23 -0700400 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700401
402 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700403 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700404 // there is no existing paint colorfilter, so we can just return the imagefilter's
405 return imgCF;
406 }
407
408 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
409 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700410 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700411}
412
senorblanco87e066e2015-10-28 11:23:36 -0700413/**
414 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
415 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
416 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
417 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
418 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
419 * conservative "effective" bounds based on the settings in the paint... with one exception. This
420 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
421 * deliberately ignored.
422 */
423static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
424 const SkRect& rawBounds,
425 SkRect* storage) {
426 SkPaint tmpUnfiltered(paint);
427 tmpUnfiltered.setImageFilter(nullptr);
428 if (tmpUnfiltered.canComputeFastBounds()) {
429 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
430 } else {
431 return rawBounds;
432 }
433}
434
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435class AutoDrawLooper {
436public:
senorblanco87e066e2015-10-28 11:23:36 -0700437 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
438 // paint. It's used to determine the size of the offscreen layer for filters.
439 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700440 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700441 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000442 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800443#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800445#else
446 fFilter = nullptr;
447#endif
reed4a8126e2014-09-22 07:29:03 -0700448 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000449 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700450 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000451 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452
reedd053ce92016-03-22 10:17:23 -0700453 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700454 if (simplifiedCF) {
455 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700456 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700457 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700458 fPaint = paint;
459 }
460
461 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700462 /**
463 * We implement ImageFilters for a given draw by creating a layer, then applying the
464 * imagefilter to the pixels of that layer (its backing surface/image), and then
465 * we call restore() to xfer that layer to the main canvas.
466 *
467 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
468 * 2. Generate the src pixels:
469 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
470 * return (fPaint). We then draw the primitive (using srcover) into a cleared
471 * buffer/surface.
472 * 3. Restore the layer created in #1
473 * The imagefilter is passed the buffer/surface from the layer (now filled with the
474 * src pixels of the primitive). It returns a new "filtered" buffer, which we
475 * draw onto the previous layer using the xfermode from the original paint.
476 */
reed@google.com8926b162012-03-23 15:36:36 +0000477 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500478 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700479 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700480 SkRect storage;
481 if (rawBounds) {
482 // Make rawBounds include all paint outsets except for those due to image filters.
483 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
484 }
reedbfd5f172016-01-07 11:28:08 -0800485 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700486 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700487 fTempLayerForImageFilter = true;
488 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000489 }
490
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000491 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500492 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000493 fIsSimple = false;
494 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700495 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000496 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700497 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000498 }
499 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000500
reed@android.com8a1c16f2008-12-17 15:59:43 +0000501 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700502 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000503 fCanvas->internalRestore();
504 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000505 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000507
reed@google.com4e2b3d32011-04-07 14:18:59 +0000508 const SkPaint& paint() const {
509 SkASSERT(fPaint);
510 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000511 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000512
reed@google.com129ec222012-05-15 13:24:09 +0000513 bool next(SkDrawFilter::Type drawType) {
514 if (fDone) {
515 return false;
516 } else if (fIsSimple) {
517 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000518 return !fPaint->nothingToDraw();
519 } else {
520 return this->doNext(drawType);
521 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000522 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000523
reed@android.com8a1c16f2008-12-17 15:59:43 +0000524private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500525 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700526 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000527 SkCanvas* fCanvas;
528 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000529 SkDrawFilter* fFilter;
530 const SkPaint* fPaint;
531 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700532 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000533 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000534 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000535 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500536 char fStorage[48];
537 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000538
539 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540};
541
reed@google.com129ec222012-05-15 13:24:09 +0000542bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700543 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000544 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700545 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000546
reeddbc3cef2015-04-29 12:18:57 -0700547 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
548 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000549
reed5c476fb2015-04-20 08:04:21 -0700550 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700551 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700552 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000553 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000554
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000555 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000556 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000557 return false;
558 }
559 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000560 if (!fFilter->filter(paint, drawType)) {
561 fDone = true;
562 return false;
563 }
halcanary96fcdcc2015-08-27 07:41:13 -0700564 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000565 // no looper means we only draw once
566 fDone = true;
567 }
568 }
569 fPaint = paint;
570
571 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000572 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000573 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000574 }
575
576 // call this after any possible paint modifiers
577 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700578 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000579 return false;
580 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000581 return true;
582}
583
reed@android.com8a1c16f2008-12-17 15:59:43 +0000584////////// macros to place around the internal draw calls //////////////////
585
reed3aafe112016-08-18 12:45:34 -0700586#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
587 this->predrawNotify(); \
588 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
589 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800590 SkDrawIter iter(this);
591
592
reed@google.com8926b162012-03-23 15:36:36 +0000593#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000594 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700595 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000596 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000597 SkDrawIter iter(this);
598
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000599#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000600 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700601 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000602 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000604
reedc83a2972015-07-16 07:40:45 -0700605#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
606 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700607 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700608 while (looper.next(type)) { \
609 SkDrawIter iter(this);
610
reed@google.com4e2b3d32011-04-07 14:18:59 +0000611#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612
613////////////////////////////////////////////////////////////////////////////
614
msarettfbfa2582016-08-12 08:29:08 -0700615static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
616 if (bounds.isEmpty()) {
617 return SkRect::MakeEmpty();
618 }
619
620 // Expand bounds out by 1 in case we are anti-aliasing. We store the
621 // bounds as floats to enable a faster quick reject implementation.
622 SkRect dst;
623 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
624 return dst;
625}
626
mtkleinfeaadee2015-04-08 11:25:48 -0700627void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
628 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700629 fMCRec->reset(bounds);
630
631 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500632 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400633 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700634 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700635 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700636}
637
reedd9544982014-09-09 18:46:22 -0700638SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800639 if (device && device->forceConservativeRasterClip()) {
640 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
641 }
reed42b73eb2015-11-20 13:42:42 -0800642
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000643 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800644 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700645 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700646#ifdef SK_EXPERIMENTAL_SHADOWING
647 fLights = nullptr;
648#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649
650 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500651 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500652 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700653 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654
reeda499f902015-05-01 09:34:31 -0700655 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
656 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita53f77bd2017-04-28 13:48:37 -0400657 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700658
reed@android.com8a1c16f2008-12-17 15:59:43 +0000659 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000660
halcanary96fcdcc2015-08-27 07:41:13 -0700661 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000662
reedf92c8662014-08-18 08:02:43 -0700663 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700664 // The root device and the canvas should always have the same pixel geometry
665 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800666 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700667 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500668
Mike Reedc42a1cd2017-02-14 14:25:14 -0500669 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700670 }
msarettfbfa2582016-08-12 08:29:08 -0700671
reedf92c8662014-08-18 08:02:43 -0700672 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000673}
674
reed@google.comcde92112011-07-06 20:00:52 +0000675SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000676 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700677 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000678{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000679 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000680
halcanary96fcdcc2015-08-27 07:41:13 -0700681 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000682}
683
reed96a857e2015-01-25 10:33:58 -0800684SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000685 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800686 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000687{
688 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700689
Mike Reed566e53c2017-03-10 10:49:45 -0500690 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700691 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700692}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000693
reed78e27682014-11-19 08:04:34 -0800694SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700695 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700696 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700697{
698 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700699
Mike Reed566e53c2017-03-10 10:49:45 -0500700 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
701 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700702}
703
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000704SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000705 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700706 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000707{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000708 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700709
reedd9544982014-09-09 18:46:22 -0700710 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000711}
712
robertphillipsfcf78292015-06-19 11:49:52 -0700713SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
714 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700715 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700716{
717 inc_canvas();
718
719 this->init(device, flags);
720}
721
reed4a8126e2014-09-22 07:29:03 -0700722SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700723 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700724 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700725{
726 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700727
Hal Canary704cd322016-11-07 14:13:52 -0500728 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
729 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700730}
reed29c857d2014-09-21 10:25:07 -0700731
Mike Reed356f7c22017-01-10 11:58:39 -0500732SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
733 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700734 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
735 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500736 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700737{
738 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700739
Mike Reed356f7c22017-01-10 11:58:39 -0500740 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500741 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742}
743
Mike Reed356f7c22017-01-10 11:58:39 -0500744SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
745
Matt Sarett31f99ce2017-04-11 08:46:01 -0400746#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
747SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
748 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
749 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
750 , fAllocator(nullptr)
751{
752 inc_canvas();
753
754 SkBitmap tmp(bitmap);
755 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
756 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
757 this->init(device.get(), kDefault_InitFlags);
758}
759#endif
760
reed@android.com8a1c16f2008-12-17 15:59:43 +0000761SkCanvas::~SkCanvas() {
762 // free up the contents of our deque
763 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000764
reed@android.com8a1c16f2008-12-17 15:59:43 +0000765 this->internalRestore(); // restore the last, since we're going away
766
halcanary385fe4d2015-08-26 13:07:48 -0700767 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000768
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769 dec_canvas();
770}
771
fmalita53d9f1c2016-01-25 06:23:54 -0800772#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773SkDrawFilter* SkCanvas::getDrawFilter() const {
774 return fMCRec->fFilter;
775}
776
777SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700778 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000779 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
780 return filter;
781}
fmalita77650002016-01-21 18:47:11 -0800782#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000783
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000784SkMetaData& SkCanvas::getMetaData() {
785 // metadata users are rare, so we lazily allocate it. If that changes we
786 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700787 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000788 fMetaData = new SkMetaData;
789 }
790 return *fMetaData;
791}
792
reed@android.com8a1c16f2008-12-17 15:59:43 +0000793///////////////////////////////////////////////////////////////////////////////
794
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000795void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700796 this->onFlush();
797}
798
799void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000800 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000801 if (device) {
802 device->flush();
803 }
804}
805
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000806SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000807 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000808 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
809}
810
senorblancoafc7cce2016-02-02 18:44:15 -0800811SkIRect SkCanvas::getTopLayerBounds() const {
812 SkBaseDevice* d = this->getTopDevice();
813 if (!d) {
814 return SkIRect::MakeEmpty();
815 }
816 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
817}
818
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000819SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000820 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000821 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000822 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400823 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824}
825
Florin Malita0ed3b642017-01-13 16:56:38 +0000826SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400827 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000828}
829
reed96472de2014-12-10 09:53:42 -0800830bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000831 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000832 if (!device) {
833 return false;
834 }
mtkleinf0f14112014-12-12 08:46:25 -0800835
Matt Sarett03dd6d52017-01-23 12:15:09 -0500836 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000837}
838
Mike Reed12e946b2017-04-17 10:53:29 -0400839bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
840 return pm.addr() && this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y);
841}
842
843bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
844 SkPixmap pm;
845 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
846}
847
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000848bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400849 SkPixmap pm;
850 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700851 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000852 }
853 return false;
854}
855
Matt Sarett03dd6d52017-01-23 12:15:09 -0500856bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000857 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000858 SkBaseDevice* device = this->getDevice();
859 if (!device) {
860 return false;
861 }
862
Matt Sarett03dd6d52017-01-23 12:15:09 -0500863 // This check gives us an early out and prevents generation ID churn on the surface.
864 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
865 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
866 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
867 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000868 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000869
Matt Sarett03dd6d52017-01-23 12:15:09 -0500870 // Tell our owning surface to bump its generation ID.
871 const bool completeOverwrite =
872 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700873 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700874
Matt Sarett03dd6d52017-01-23 12:15:09 -0500875 // This can still fail, most notably in the case of a invalid color type or alpha type
876 // conversion. We could pull those checks into this function and avoid the unnecessary
877 // generation ID bump. But then we would be performing those checks twice, since they
878 // are also necessary at the bitmap/pixmap entry points.
879 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000880}
reed@google.com51df9e32010-12-23 19:29:18 +0000881
reed@android.com8a1c16f2008-12-17 15:59:43 +0000882//////////////////////////////////////////////////////////////////////////////
883
reed2ff1fce2014-12-11 07:07:37 -0800884void SkCanvas::checkForDeferredSave() {
885 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800886 this->doSave();
887 }
888}
889
reedf0090cb2014-11-26 08:55:51 -0800890int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800891#ifdef SK_DEBUG
892 int count = 0;
893 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
894 for (;;) {
895 const MCRec* rec = (const MCRec*)iter.next();
896 if (!rec) {
897 break;
898 }
899 count += 1 + rec->fDeferredSaveCount;
900 }
901 SkASSERT(count == fSaveCount);
902#endif
903 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800904}
905
906int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800907 fSaveCount += 1;
908 fMCRec->fDeferredSaveCount += 1;
909 return this->getSaveCount() - 1; // return our prev value
910}
911
912void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800913 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700914
915 SkASSERT(fMCRec->fDeferredSaveCount > 0);
916 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800917 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800918}
919
920void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800921 if (fMCRec->fDeferredSaveCount > 0) {
922 SkASSERT(fSaveCount > 1);
923 fSaveCount -= 1;
924 fMCRec->fDeferredSaveCount -= 1;
925 } else {
926 // check for underflow
927 if (fMCStack.count() > 1) {
928 this->willRestore();
929 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700930 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800931 this->internalRestore();
932 this->didRestore();
933 }
reedf0090cb2014-11-26 08:55:51 -0800934 }
935}
936
937void SkCanvas::restoreToCount(int count) {
938 // sanity check
939 if (count < 1) {
940 count = 1;
941 }
mtkleinf0f14112014-12-12 08:46:25 -0800942
reedf0090cb2014-11-26 08:55:51 -0800943 int n = this->getSaveCount() - count;
944 for (int i = 0; i < n; ++i) {
945 this->restore();
946 }
947}
948
reed2ff1fce2014-12-11 07:07:37 -0800949void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000950 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700951 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000952 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000953
Mike Reedc42a1cd2017-02-14 14:25:14 -0500954 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955}
956
reed4960eee2015-12-18 07:09:18 -0800957bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800958 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000959}
960
reed4960eee2015-12-18 07:09:18 -0800961bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700962 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500963 SkIRect clipBounds = this->getDeviceClipBounds();
964 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000965 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000966 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000967
reed96e657d2015-03-10 17:30:07 -0700968 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
969
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000970 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700971 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800972 if (bounds && !imageFilter->canComputeFastBounds()) {
973 bounds = nullptr;
974 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000975 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000976 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700977 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000979
reed96e657d2015-03-10 17:30:07 -0700980 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981 r.roundOut(&ir);
982 // early exit if the layer's bounds are clipped out
983 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -0800984 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -0500985 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -0700986 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -0700987 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000988 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000989 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000990 }
991 } else { // no user bounds, so just use the clip
992 ir = clipBounds;
993 }
reed180aec42015-03-11 10:39:04 -0700994 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000995
reed4960eee2015-12-18 07:09:18 -0800996 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700997 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700998 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700999 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001000 }
1001
1002 if (intersection) {
1003 *intersection = ir;
1004 }
1005 return true;
1006}
1007
reed4960eee2015-12-18 07:09:18 -08001008
reed4960eee2015-12-18 07:09:18 -08001009int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1010 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001011}
1012
reed70ee31b2015-12-10 13:44:45 -08001013int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001014 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1015}
1016
1017int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001018 SkTCopyOnFirstWrite<SaveLayerRec> rec(origRec);
reed4960eee2015-12-18 07:09:18 -08001019 if (gIgnoreSaveLayerBounds) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001020 rec.writable()->fBounds = nullptr;
reed4960eee2015-12-18 07:09:18 -08001021 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001022
1023 SaveLayerStrategy strategy = this->getSaveLayerStrategy(*rec);
reed4960eee2015-12-18 07:09:18 -08001024 fSaveCount += 1;
Florin Malita53f77bd2017-04-28 13:48:37 -04001025 this->internalSaveLayer(*rec, strategy);
reed4960eee2015-12-18 07:09:18 -08001026 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001027}
1028
reeda2217ef2016-07-20 06:04:34 -07001029void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001030 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001031 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001032 SkDraw draw;
1033 SkRasterClip rc;
1034 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1035 if (!dst->accessPixels(&draw.fDst)) {
1036 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001037 }
reeda2217ef2016-07-20 06:04:34 -07001038 draw.fMatrix = &SkMatrix::I();
1039 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001040
1041 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001042 if (filter) {
1043 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1044 }
reeda2217ef2016-07-20 06:04:34 -07001045
Mike Reedc42a1cd2017-02-14 14:25:14 -05001046 int x = src->getOrigin().x() - dstOrigin.x();
1047 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001048 auto special = src->snapSpecial();
1049 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001050 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -07001051 }
robertphillips7354a4b2015-12-16 05:08:27 -08001052}
reed70ee31b2015-12-10 13:44:45 -08001053
reed129ed1c2016-02-22 06:42:31 -08001054static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1055 const SkPaint* paint) {
1056 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1057 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001058 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001059 const bool hasImageFilter = paint && paint->getImageFilter();
1060
1061 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1062 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1063 // force to L32
1064 return SkImageInfo::MakeN32(w, h, alphaType);
1065 } else {
1066 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001067 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001068 }
1069}
1070
reed4960eee2015-12-18 07:09:18 -08001071void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1072 const SkRect* bounds = rec.fBounds;
1073 const SkPaint* paint = rec.fPaint;
1074 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1075
reed8c30a812016-04-20 16:36:51 -07001076 SkLazyPaint lazyP;
1077 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1078 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001079 SkMatrix remainder;
1080 SkSize scale;
1081 /*
1082 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1083 * but they do handle scaling. To accommodate this, we do the following:
1084 *
1085 * 1. Stash off the current CTM
1086 * 2. Decompose the CTM into SCALE and REMAINDER
1087 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1088 * contains the REMAINDER
1089 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1090 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1091 * of the original imagefilter, and draw that (via drawSprite)
1092 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1093 *
1094 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1095 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1096 */
reed96a04f32016-04-25 09:25:15 -07001097 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001098 stashedMatrix.decomposeScale(&scale, &remainder))
1099 {
1100 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1101 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1102 SkPaint* p = lazyP.set(*paint);
1103 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1104 SkFilterQuality::kLow_SkFilterQuality,
1105 sk_ref_sp(imageFilter)));
1106 imageFilter = p->getImageFilter();
1107 paint = p;
1108 }
reed8c30a812016-04-20 16:36:51 -07001109
junov@chromium.orga907ac32012-02-24 21:54:07 +00001110 // do this before we create the layer. We don't call the public save() since
1111 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001112 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001113
junov@chromium.orga907ac32012-02-24 21:54:07 +00001114 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001115 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001116 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001117 }
1118
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001119 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1120 // the clipRectBounds() call above?
1121 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001122 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001123 }
1124
reed4960eee2015-12-18 07:09:18 -08001125 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001126 SkPixelGeometry geo = fProps.pixelGeometry();
1127 if (paint) {
reed76033be2015-03-14 10:54:31 -07001128 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001129 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001130 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001131 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001132 }
1133 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001134
robertphillips5139e502016-07-19 05:10:40 -07001135 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001136 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001137 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001138 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001139 }
reedb2db8982014-11-13 12:41:02 -08001140
robertphillips5139e502016-07-19 05:10:40 -07001141 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001142 paint);
1143
Hal Canary704cd322016-11-07 14:13:52 -05001144 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001145 {
reed70ee31b2015-12-10 13:44:45 -08001146 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001147 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001148 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001149 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001150 preserveLCDText,
1151 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001152 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1153 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001154 return;
reed61f501f2015-04-29 08:34:00 -07001155 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001156 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001157 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001158
Mike Reedb43a3e02017-02-11 10:18:58 -05001159 // only have a "next" if this new layer doesn't affect the clip (rare)
1160 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001161 fMCRec->fLayer = layer;
1162 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001163
Mike Reedc61abee2017-02-28 17:45:27 -05001164 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001165 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001166 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001167 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001168
Mike Reedc42a1cd2017-02-14 14:25:14 -05001169 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1170
1171 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1172 if (layer->fNext) {
1173 // need to punch a hole in the previous device, so we don't draw there, given that
1174 // the new top-layer will allow drawing to happen "below" it.
1175 SkRegion hole(ir);
1176 do {
1177 layer = layer->fNext;
1178 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1179 } while (layer->fNext);
1180 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181}
1182
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001183int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001184 if (0xFF == alpha) {
1185 return this->saveLayer(bounds, nullptr);
1186 } else {
1187 SkPaint tmpPaint;
1188 tmpPaint.setAlpha(alpha);
1189 return this->saveLayer(bounds, &tmpPaint);
1190 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001191}
1192
reed@android.com8a1c16f2008-12-17 15:59:43 +00001193void SkCanvas::internalRestore() {
1194 SkASSERT(fMCStack.count() != 0);
1195
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001196 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001197 DeviceCM* layer = fMCRec->fLayer; // may be null
1198 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001199 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200
1201 // now do the normal restore()
1202 fMCRec->~MCRec(); // balanced in save()
1203 fMCStack.pop_back();
1204 fMCRec = (MCRec*)fMCStack.back();
1205
Mike Reedc42a1cd2017-02-14 14:25:14 -05001206 if (fMCRec) {
1207 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1208 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001209
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1211 since if we're being recorded, we don't want to record this (the
1212 recorder will have already recorded the restore).
1213 */
bsalomon49f085d2014-09-05 13:34:00 -07001214 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001215 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001216 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001217 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001218 layer->fPaint.get(),
1219 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001220 // restore what we smashed in internalSaveLayer
1221 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001222 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001223 delete layer;
reedb679ca82015-04-07 04:40:48 -07001224 } else {
1225 // we're at the root
reeda499f902015-05-01 09:34:31 -07001226 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001227 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001228 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001229 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001230 }
msarettfbfa2582016-08-12 08:29:08 -07001231
1232 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001233 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001234 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1235 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001236}
1237
reede8f30622016-03-23 18:59:25 -07001238sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001239 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001240 props = &fProps;
1241 }
1242 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001243}
1244
reede8f30622016-03-23 18:59:25 -07001245sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001246 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001247 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001248}
1249
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001250SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001251 return this->onImageInfo();
1252}
1253
1254SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001255 SkBaseDevice* dev = this->getDevice();
1256 if (dev) {
1257 return dev->imageInfo();
1258 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001259 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001260 }
1261}
1262
brianosman898235c2016-04-06 07:38:23 -07001263bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001264 return this->onGetProps(props);
1265}
1266
1267bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001268 SkBaseDevice* dev = this->getDevice();
1269 if (dev) {
1270 if (props) {
1271 *props = fProps;
1272 }
1273 return true;
1274 } else {
1275 return false;
1276 }
1277}
1278
reed6ceeebd2016-03-09 14:26:26 -08001279bool SkCanvas::peekPixels(SkPixmap* pmap) {
1280 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001281}
1282
reed884e97c2015-05-26 11:31:54 -07001283bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001284 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001285 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001286}
1287
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001288void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001289 SkPixmap pmap;
1290 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001291 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001292 }
1293 if (info) {
1294 *info = pmap.info();
1295 }
1296 if (rowBytes) {
1297 *rowBytes = pmap.rowBytes();
1298 }
1299 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001300 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001301 }
reed884e97c2015-05-26 11:31:54 -07001302 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001303}
1304
reed884e97c2015-05-26 11:31:54 -07001305bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001306 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001307 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001308}
1309
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311
Florin Malita53f77bd2017-04-28 13:48:37 -04001312void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1313 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001315 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001316 paint = &tmp;
1317 }
reed@google.com4b226022011-01-11 18:32:13 +00001318
reed@google.com8926b162012-03-23 15:36:36 +00001319 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001320
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001322 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001323 paint = &looper.paint();
1324 SkImageFilter* filter = paint->getImageFilter();
1325 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001326 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001327 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1328 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001329 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1330 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001331 }
reed@google.com76dd2772012-01-05 21:15:07 +00001332 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001333 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001334 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335 }
reeda2217ef2016-07-20 06:04:34 -07001336
reed@google.com4e2b3d32011-04-07 14:18:59 +00001337 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338}
1339
reed32704672015-12-16 08:27:10 -08001340/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001341
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001342void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001343 if (dx || dy) {
1344 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001345 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001346
reedfe69b502016-09-12 06:31:48 -07001347 // Translate shouldn't affect the is-scale-translateness of the matrix.
1348 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001349
Mike Reedc42a1cd2017-02-14 14:25:14 -05001350 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001351
reedfe69b502016-09-12 06:31:48 -07001352 this->didTranslate(dx,dy);
1353 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001354}
1355
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001356void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001357 SkMatrix m;
1358 m.setScale(sx, sy);
1359 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001360}
1361
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001362void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001363 SkMatrix m;
1364 m.setRotate(degrees);
1365 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001366}
1367
bungeman7438bfc2016-07-12 15:01:19 -07001368void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1369 SkMatrix m;
1370 m.setRotate(degrees, px, py);
1371 this->concat(m);
1372}
1373
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001374void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001375 SkMatrix m;
1376 m.setSkew(sx, sy);
1377 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001378}
1379
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001380void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001381 if (matrix.isIdentity()) {
1382 return;
1383 }
1384
reed2ff1fce2014-12-11 07:07:37 -08001385 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001386 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001387 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001388
Mike Reed7627fa52017-02-08 10:07:53 -05001389 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001390
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001391 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001392}
1393
reed8c30a812016-04-20 16:36:51 -07001394void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001395 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001396 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001397
Mike Reedc42a1cd2017-02-14 14:25:14 -05001398 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001399}
1400
1401void SkCanvas::setMatrix(const SkMatrix& matrix) {
1402 this->checkForDeferredSave();
1403 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001404 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001405}
1406
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001408 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409}
1410
vjiaoblack95302da2016-07-21 10:25:54 -07001411#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001412void SkCanvas::translateZ(SkScalar z) {
1413 this->checkForDeferredSave();
1414 this->fMCRec->fCurDrawDepth += z;
1415 this->didTranslateZ(z);
1416}
1417
1418SkScalar SkCanvas::getZ() const {
1419 return this->fMCRec->fCurDrawDepth;
1420}
1421
vjiaoblack95302da2016-07-21 10:25:54 -07001422void SkCanvas::setLights(sk_sp<SkLights> lights) {
1423 this->fLights = lights;
1424}
1425
1426sk_sp<SkLights> SkCanvas::getLights() const {
1427 return this->fLights;
1428}
1429#endif
1430
reed@android.com8a1c16f2008-12-17 15:59:43 +00001431//////////////////////////////////////////////////////////////////////////////
1432
Mike Reedc1f77742016-12-09 09:00:50 -05001433void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001434 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001435 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1436 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001437}
1438
Mike Reedc1f77742016-12-09 09:00:50 -05001439void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001440 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001441
Mike Reed7627fa52017-02-08 10:07:53 -05001442 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001443
reedc64eff52015-11-21 12:39:45 -08001444 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001445 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1446 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001447 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448}
1449
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001450void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1451 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001452 if (fClipRestrictionRect.isEmpty()) {
1453 // we notify the device, but we *dont* resolve deferred saves (since we're just
1454 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001455 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001456 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001457 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001458 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001459 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001460 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001461 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1462 }
1463}
1464
Mike Reedc1f77742016-12-09 09:00:50 -05001465void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001466 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001467 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001468 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001469 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1470 } else {
1471 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001472 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001473}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001474
Mike Reedc1f77742016-12-09 09:00:50 -05001475void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001476 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001477
Brian Salomona3b45d42016-10-03 11:36:16 -04001478 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001479
Mike Reed7627fa52017-02-08 10:07:53 -05001480 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001481
Brian Salomona3b45d42016-10-03 11:36:16 -04001482 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1483 isAA);
1484 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001485}
1486
Mike Reedc1f77742016-12-09 09:00:50 -05001487void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001488 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001489 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001490
1491 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1492 SkRect r;
1493 if (path.isRect(&r)) {
1494 this->onClipRect(r, op, edgeStyle);
1495 return;
1496 }
1497 SkRRect rrect;
1498 if (path.isOval(&r)) {
1499 rrect.setOval(r);
1500 this->onClipRRect(rrect, op, edgeStyle);
1501 return;
1502 }
1503 if (path.isRRect(&rrect)) {
1504 this->onClipRRect(rrect, op, edgeStyle);
1505 return;
1506 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001507 }
robertphillips39f05382015-11-24 09:30:12 -08001508
1509 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001510}
1511
Mike Reedc1f77742016-12-09 09:00:50 -05001512void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001513 AutoValidateClip avc(this);
1514
Brian Salomona3b45d42016-10-03 11:36:16 -04001515 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001516
Mike Reed7627fa52017-02-08 10:07:53 -05001517 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001518
Brian Salomona3b45d42016-10-03 11:36:16 -04001519 const SkPath* rasterClipPath = &path;
1520 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001521 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1522 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001523 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001524}
1525
Mike Reedc1f77742016-12-09 09:00:50 -05001526void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001527 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001528 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001529}
1530
Mike Reedc1f77742016-12-09 09:00:50 -05001531void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001532 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001533
reed@google.com5c3d1472011-02-22 19:12:23 +00001534 AutoValidateClip avc(this);
1535
reed73603f32016-09-20 08:42:38 -07001536 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001537 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001538}
1539
reed@google.com819c9212011-02-23 18:56:55 +00001540#ifdef SK_DEBUG
1541void SkCanvas::validateClip() const {
1542 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001543 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001544 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001545 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001546 return;
1547 }
reed@google.com819c9212011-02-23 18:56:55 +00001548}
1549#endif
1550
Mike Reeda1361362017-03-07 09:37:29 -05001551bool SkCanvas::androidFramework_isClipAA() const {
1552 bool containsAA = false;
1553
1554 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1555
1556 return containsAA;
1557}
1558
1559class RgnAccumulator {
1560 SkRegion* fRgn;
1561public:
1562 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1563 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1564 SkIPoint origin = device->getOrigin();
1565 if (origin.x() | origin.y()) {
1566 rgn->translate(origin.x(), origin.y());
1567 }
1568 fRgn->op(*rgn, SkRegion::kUnion_Op);
1569 }
1570};
1571
1572void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1573 RgnAccumulator accum(rgn);
1574 SkRegion tmp;
1575
1576 rgn->setEmpty();
1577 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001578}
1579
reed@google.com5c3d1472011-02-22 19:12:23 +00001580///////////////////////////////////////////////////////////////////////////////
1581
reed@google.com754de5f2014-02-24 19:38:20 +00001582bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001583 return fMCRec->fRasterClip.isEmpty();
1584
1585 // TODO: should we only use the conservative answer in a recording canvas?
1586#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001587 SkBaseDevice* dev = this->getTopDevice();
1588 // if no device we return true
1589 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001590#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001591}
1592
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001593bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001594 SkBaseDevice* dev = this->getTopDevice();
1595 // if no device we return false
1596 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001597}
1598
msarettfbfa2582016-08-12 08:29:08 -07001599static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1600#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1601 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1602 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1603 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1604 return 0xF != _mm_movemask_ps(mask);
1605#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1606 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1607 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1608 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1609 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1610#else
1611 SkRect devRectAsRect;
1612 SkRect devClipAsRect;
1613 devRect.store(&devRectAsRect.fLeft);
1614 devClip.store(&devClipAsRect.fLeft);
1615 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1616#endif
1617}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001618
msarettfbfa2582016-08-12 08:29:08 -07001619// It's important for this function to not be inlined. Otherwise the compiler will share code
1620// between the fast path and the slow path, resulting in two slow paths.
1621static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1622 const SkMatrix& matrix) {
1623 SkRect deviceRect;
1624 matrix.mapRect(&deviceRect, src);
1625 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1626}
1627
1628bool SkCanvas::quickReject(const SkRect& src) const {
1629#ifdef SK_DEBUG
1630 // Verify that fDeviceClipBounds are set properly.
1631 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001632 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001633 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001634 } else {
msarettfbfa2582016-08-12 08:29:08 -07001635 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001636 }
msarettfbfa2582016-08-12 08:29:08 -07001637
msarett9637ea92016-08-18 14:03:30 -07001638 // Verify that fIsScaleTranslate is set properly.
1639 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001640#endif
1641
msarett9637ea92016-08-18 14:03:30 -07001642 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001643 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1644 }
1645
1646 // We inline the implementation of mapScaleTranslate() for the fast path.
1647 float sx = fMCRec->fMatrix.getScaleX();
1648 float sy = fMCRec->fMatrix.getScaleY();
1649 float tx = fMCRec->fMatrix.getTranslateX();
1650 float ty = fMCRec->fMatrix.getTranslateY();
1651 Sk4f scale(sx, sy, sx, sy);
1652 Sk4f trans(tx, ty, tx, ty);
1653
1654 // Apply matrix.
1655 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1656
1657 // Make sure left < right, top < bottom.
1658 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1659 Sk4f min = Sk4f::Min(ltrb, rblt);
1660 Sk4f max = Sk4f::Max(ltrb, rblt);
1661 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1662 // ARM this sequence generates the fastest (a single instruction).
1663 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1664
1665 // Check if the device rect is NaN or outside the clip.
1666 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001667}
1668
reed@google.com3b3e8952012-08-16 20:53:31 +00001669bool SkCanvas::quickReject(const SkPath& path) const {
1670 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001671}
1672
Mike Reed42e8c532017-01-23 14:09:13 -05001673SkRect SkCanvas::onGetLocalClipBounds() const {
1674 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001675 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001676 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001677 }
1678
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001679 SkMatrix inverse;
1680 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001681 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001682 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001683 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001684
Mike Reed42e8c532017-01-23 14:09:13 -05001685 SkRect bounds;
1686 SkRect r;
1687 // adjust it outwards in case we are antialiasing
1688 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001689
Mike Reed42e8c532017-01-23 14:09:13 -05001690 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1691 ibounds.fRight + inset, ibounds.fBottom + inset);
1692 inverse.mapRect(&bounds, r);
1693 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001694}
1695
Mike Reed42e8c532017-01-23 14:09:13 -05001696SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001697 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001698}
1699
reed@android.com8a1c16f2008-12-17 15:59:43 +00001700const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001701 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001702}
1703
Brian Osman11052242016-10-27 14:47:55 -04001704GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001705 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001706 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001707}
1708
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001709GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001710 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001711 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001712}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001713
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001714void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1715 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001716 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001717 if (outer.isEmpty()) {
1718 return;
1719 }
1720 if (inner.isEmpty()) {
1721 this->drawRRect(outer, paint);
1722 return;
1723 }
1724
1725 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001726 // be able to return ...
1727 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001728 //
1729 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001730 if (!outer.getBounds().contains(inner.getBounds())) {
1731 return;
1732 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001733
1734 this->onDrawDRRect(outer, inner, paint);
1735}
1736
reed41af9662015-01-05 07:49:08 -08001737// These need to stop being virtual -- clients need to override the onDraw... versions
1738
1739void SkCanvas::drawPaint(const SkPaint& paint) {
1740 this->onDrawPaint(paint);
1741}
1742
1743void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1744 this->onDrawRect(r, paint);
1745}
1746
msarettdca352e2016-08-26 06:37:45 -07001747void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1748 if (region.isEmpty()) {
1749 return;
1750 }
1751
1752 if (region.isRect()) {
1753 return this->drawIRect(region.getBounds(), paint);
1754 }
1755
1756 this->onDrawRegion(region, paint);
1757}
1758
reed41af9662015-01-05 07:49:08 -08001759void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1760 this->onDrawOval(r, paint);
1761}
1762
1763void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1764 this->onDrawRRect(rrect, paint);
1765}
1766
1767void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1768 this->onDrawPoints(mode, count, pts, paint);
1769}
1770
Mike Reede88a1cb2017-03-17 09:50:46 -04001771void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1772 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001773 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001774 this->onDrawVerticesObject(vertices.get(), mode, paint);
1775}
1776
1777void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
1778 RETURN_ON_NULL(vertices);
1779 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001780}
1781
1782void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1783 this->onDrawPath(path, paint);
1784}
1785
reeda85d4d02015-05-06 12:56:48 -07001786void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001787 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001788 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001789}
1790
reede47829b2015-08-06 10:02:53 -07001791void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1792 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001793 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001794 if (dst.isEmpty() || src.isEmpty()) {
1795 return;
1796 }
1797 this->onDrawImageRect(image, &src, dst, paint, constraint);
1798}
reed41af9662015-01-05 07:49:08 -08001799
reed84984ef2015-07-17 07:09:43 -07001800void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1801 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001802 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001803 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001804}
1805
reede47829b2015-08-06 10:02:53 -07001806void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1807 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001808 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001809 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1810 constraint);
1811}
reede47829b2015-08-06 10:02:53 -07001812
reed4c21dc52015-06-25 12:32:03 -07001813void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1814 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001815 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001816 if (dst.isEmpty()) {
1817 return;
1818 }
msarett552bca92016-08-03 06:53:26 -07001819 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1820 this->onDrawImageNine(image, center, dst, paint);
1821 } else {
reede47829b2015-08-06 10:02:53 -07001822 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001823 }
reed4c21dc52015-06-25 12:32:03 -07001824}
1825
msarett16882062016-08-16 09:31:08 -07001826void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1827 const SkPaint* paint) {
1828 RETURN_ON_NULL(image);
1829 if (dst.isEmpty()) {
1830 return;
1831 }
msarett71df2d72016-09-30 12:41:42 -07001832
1833 SkIRect bounds;
1834 Lattice latticePlusBounds = lattice;
1835 if (!latticePlusBounds.fBounds) {
1836 bounds = SkIRect::MakeWH(image->width(), image->height());
1837 latticePlusBounds.fBounds = &bounds;
1838 }
1839
1840 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1841 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001842 } else {
1843 this->drawImageRect(image, dst, paint);
1844 }
1845}
1846
reed41af9662015-01-05 07:49:08 -08001847void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001848 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001849 return;
1850 }
reed41af9662015-01-05 07:49:08 -08001851 this->onDrawBitmap(bitmap, dx, dy, paint);
1852}
1853
reede47829b2015-08-06 10:02:53 -07001854void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001855 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001856 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001857 return;
1858 }
reede47829b2015-08-06 10:02:53 -07001859 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001860}
1861
reed84984ef2015-07-17 07:09:43 -07001862void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1863 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001864 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001865}
1866
reede47829b2015-08-06 10:02:53 -07001867void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1868 SrcRectConstraint constraint) {
1869 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1870 constraint);
1871}
reede47829b2015-08-06 10:02:53 -07001872
reed41af9662015-01-05 07:49:08 -08001873void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1874 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001875 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001876 return;
1877 }
msarett552bca92016-08-03 06:53:26 -07001878 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1879 this->onDrawBitmapNine(bitmap, center, dst, paint);
1880 } else {
reeda5517e22015-07-14 10:54:12 -07001881 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001882 }
reed41af9662015-01-05 07:49:08 -08001883}
1884
msarettc573a402016-08-02 08:05:56 -07001885void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1886 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001887 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001888 return;
1889 }
msarett71df2d72016-09-30 12:41:42 -07001890
1891 SkIRect bounds;
1892 Lattice latticePlusBounds = lattice;
1893 if (!latticePlusBounds.fBounds) {
1894 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1895 latticePlusBounds.fBounds = &bounds;
1896 }
1897
1898 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1899 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001900 } else {
msarett16882062016-08-16 09:31:08 -07001901 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001902 }
msarettc573a402016-08-02 08:05:56 -07001903}
1904
reed71c3c762015-06-24 10:29:17 -07001905void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001906 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001907 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001908 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001909 if (count <= 0) {
1910 return;
1911 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001912 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001913 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001914 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001915}
1916
reedf70b5312016-03-04 16:36:20 -08001917void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1918 if (key) {
1919 this->onDrawAnnotation(rect, key, value);
1920 }
1921}
1922
reede47829b2015-08-06 10:02:53 -07001923void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1924 const SkPaint* paint, SrcRectConstraint constraint) {
1925 if (src) {
1926 this->drawImageRect(image, *src, dst, paint, constraint);
1927 } else {
1928 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1929 dst, paint, constraint);
1930 }
1931}
1932void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1933 const SkPaint* paint, SrcRectConstraint constraint) {
1934 if (src) {
1935 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1936 } else {
1937 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1938 dst, paint, constraint);
1939 }
1940}
1941
reed@android.com8a1c16f2008-12-17 15:59:43 +00001942//////////////////////////////////////////////////////////////////////////////
1943// These are the virtual drawing methods
1944//////////////////////////////////////////////////////////////////////////////
1945
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001946void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001947 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001948 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1949 }
1950}
1951
reed41af9662015-01-05 07:49:08 -08001952void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001953 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001954 this->internalDrawPaint(paint);
1955}
1956
1957void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001958 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001959
1960 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001961 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001962 }
1963
reed@google.com4e2b3d32011-04-07 14:18:59 +00001964 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001965}
1966
reed41af9662015-01-05 07:49:08 -08001967void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1968 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001969 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001970 if ((long)count <= 0) {
1971 return;
1972 }
1973
Mike Reed822128b2017-02-28 16:41:03 -05001974 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001975 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001976 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001977 // special-case 2 points (common for drawing a single line)
1978 if (2 == count) {
1979 r.set(pts[0], pts[1]);
1980 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001981 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001982 }
Mike Reed822128b2017-02-28 16:41:03 -05001983 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001984 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1985 return;
1986 }
1987 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001988 }
reed@google.coma584aed2012-05-16 14:06:02 +00001989
halcanary96fcdcc2015-08-27 07:41:13 -07001990 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001991
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001992 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001993
reed@android.com8a1c16f2008-12-17 15:59:43 +00001994 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001995 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001996 }
reed@google.com4b226022011-01-11 18:32:13 +00001997
reed@google.com4e2b3d32011-04-07 14:18:59 +00001998 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001999}
2000
reed4a167172016-08-18 17:15:25 -07002001static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2002 return ((intptr_t)paint.getImageFilter() |
2003#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2004 (intptr_t)canvas->getDrawFilter() |
2005#endif
2006 (intptr_t)paint.getLooper() ) != 0;
2007}
2008
reed41af9662015-01-05 07:49:08 -08002009void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002010 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002011 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002012 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2013 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2014 SkRect tmp(r);
2015 tmp.sort();
2016
Mike Reed822128b2017-02-28 16:41:03 -05002017 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002018 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2019 return;
2020 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002021 }
reed@google.com4b226022011-01-11 18:32:13 +00002022
reed4a167172016-08-18 17:15:25 -07002023 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002024 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002025
reed4a167172016-08-18 17:15:25 -07002026 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002027 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002028 }
2029
2030 LOOPER_END
2031 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002032 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002033 SkDrawIter iter(this);
2034 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002035 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002036 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002037 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002038}
2039
msarett44df6512016-08-25 13:54:30 -07002040void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002041 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002042 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002043 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002044 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2045 return;
2046 }
msarett44df6512016-08-25 13:54:30 -07002047 }
2048
Mike Reed822128b2017-02-28 16:41:03 -05002049 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002050
2051 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002052 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002053 }
2054
2055 LOOPER_END
2056}
2057
reed41af9662015-01-05 07:49:08 -08002058void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002059 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002060 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002061 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002062 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2063 return;
2064 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002065 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002066
Mike Reed822128b2017-02-28 16:41:03 -05002067 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002068
2069 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002070 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002071 }
2072
2073 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002074}
2075
bsalomonac3aa242016-08-19 11:25:19 -07002076void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2077 SkScalar sweepAngle, bool useCenter,
2078 const SkPaint& paint) {
2079 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002080 if (paint.canComputeFastBounds()) {
2081 SkRect storage;
2082 // Note we're using the entire oval as the bounds.
2083 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2084 return;
2085 }
bsalomonac3aa242016-08-19 11:25:19 -07002086 }
2087
Mike Reed822128b2017-02-28 16:41:03 -05002088 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002089
2090 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002091 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002092 }
2093
2094 LOOPER_END
2095}
2096
reed41af9662015-01-05 07:49:08 -08002097void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002098 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002099 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002100 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002101 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2102 return;
2103 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002104 }
2105
2106 if (rrect.isRect()) {
2107 // call the non-virtual version
2108 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002109 return;
2110 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002111 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002112 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2113 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002114 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002115
Mike Reed822128b2017-02-28 16:41:03 -05002116 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002117
2118 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002119 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002120 }
2121
2122 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002123}
2124
Mike Reed822128b2017-02-28 16:41:03 -05002125void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002126 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002127 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002128 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2129 return;
2130 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002131 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002132
Mike Reed822128b2017-02-28 16:41:03 -05002133 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002134
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002135 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002136 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002137 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002138
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002139 LOOPER_END
2140}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002141
reed41af9662015-01-05 07:49:08 -08002142void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002143 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002144 if (!path.isFinite()) {
2145 return;
2146 }
2147
Mike Reed822128b2017-02-28 16:41:03 -05002148 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002149 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002150 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002151 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2152 return;
2153 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002154 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002155
Mike Reed822128b2017-02-28 16:41:03 -05002156 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002157 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002158 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002159 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002160 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002161 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002162
Mike Reed822128b2017-02-28 16:41:03 -05002163 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002164
2165 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002166 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002167 }
2168
reed@google.com4e2b3d32011-04-07 14:18:59 +00002169 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002170}
2171
reed262a71b2015-12-05 13:07:27 -08002172bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002173 if (!paint.getImageFilter()) {
2174 return false;
2175 }
2176
2177 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002178 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002179 return false;
2180 }
2181
2182 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2183 // Once we can filter and the filter will return a result larger than itself, we should be
2184 // able to remove this constraint.
2185 // skbug.com/4526
2186 //
2187 SkPoint pt;
2188 ctm.mapXY(x, y, &pt);
2189 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2190 return ir.contains(fMCRec->fRasterClip.getBounds());
2191}
2192
reeda85d4d02015-05-06 12:56:48 -07002193void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002194 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002195 SkRect bounds = SkRect::MakeXYWH(x, y,
2196 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002197 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002198 SkRect tmp = bounds;
2199 if (paint) {
2200 paint->computeFastBounds(tmp, &tmp);
2201 }
2202 if (this->quickReject(tmp)) {
2203 return;
2204 }
reeda85d4d02015-05-06 12:56:48 -07002205 }
halcanary9d524f22016-03-29 09:03:52 -07002206
reeda85d4d02015-05-06 12:56:48 -07002207 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002208 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002209 paint = lazy.init();
2210 }
reed262a71b2015-12-05 13:07:27 -08002211
reeda2217ef2016-07-20 06:04:34 -07002212 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002213 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2214 *paint);
2215 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002216 special = this->getDevice()->makeSpecial(image);
2217 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002218 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002219 }
2220 }
2221
reed262a71b2015-12-05 13:07:27 -08002222 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2223
reeda85d4d02015-05-06 12:56:48 -07002224 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002225 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002226 if (special) {
2227 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002228 iter.fDevice->ctm().mapXY(x, y, &pt);
2229 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002230 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002231 SkScalarRoundToInt(pt.fY), pnt,
2232 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002233 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002234 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002235 }
reeda85d4d02015-05-06 12:56:48 -07002236 }
halcanary9d524f22016-03-29 09:03:52 -07002237
reeda85d4d02015-05-06 12:56:48 -07002238 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002239}
2240
reed41af9662015-01-05 07:49:08 -08002241void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002242 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002243 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002244 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002245 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002246 if (paint) {
2247 paint->computeFastBounds(dst, &storage);
2248 }
2249 if (this->quickReject(storage)) {
2250 return;
2251 }
reeda85d4d02015-05-06 12:56:48 -07002252 }
2253 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002254 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002255 paint = lazy.init();
2256 }
halcanary9d524f22016-03-29 09:03:52 -07002257
senorblancoc41e7e12015-12-07 12:51:30 -08002258 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002259 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002260
reeda85d4d02015-05-06 12:56:48 -07002261 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002262 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002263 }
halcanary9d524f22016-03-29 09:03:52 -07002264
reeda85d4d02015-05-06 12:56:48 -07002265 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002266}
2267
reed41af9662015-01-05 07:49:08 -08002268void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002269 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002270 SkDEBUGCODE(bitmap.validate();)
2271
reed33366972015-10-08 09:22:02 -07002272 if (bitmap.drawsNothing()) {
2273 return;
2274 }
2275
2276 SkLazyPaint lazy;
2277 if (nullptr == paint) {
2278 paint = lazy.init();
2279 }
2280
Mike Reed822128b2017-02-28 16:41:03 -05002281 SkRect bounds;
2282 bitmap.getBounds(&bounds);
2283 bounds.offset(x, y);
2284 bool canFastBounds = paint->canComputeFastBounds();
2285 if (canFastBounds) {
2286 SkRect storage;
2287 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002288 return;
2289 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290 }
reed@google.com4b226022011-01-11 18:32:13 +00002291
reeda2217ef2016-07-20 06:04:34 -07002292 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002293 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2294 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002295 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002296 special = this->getDevice()->makeSpecial(bitmap);
2297 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002298 drawAsSprite = false;
2299 }
2300 }
2301
Mike Reed822128b2017-02-28 16:41:03 -05002302 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2303
2304 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002305
2306 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002307 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002308 if (special) {
reed262a71b2015-12-05 13:07:27 -08002309 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002310 iter.fDevice->ctm().mapXY(x, y, &pt);
2311 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002312 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002313 SkScalarRoundToInt(pt.fY), pnt,
2314 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002315 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002316 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002317 }
reed33366972015-10-08 09:22:02 -07002318 }
msarettfbfa2582016-08-12 08:29:08 -07002319
reed33366972015-10-08 09:22:02 -07002320 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002321}
2322
reed@google.com9987ec32011-09-07 11:57:52 +00002323// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002324void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002325 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002326 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002327 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002328 return;
2329 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002330
halcanary96fcdcc2015-08-27 07:41:13 -07002331 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002332 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002333 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2334 return;
2335 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002336 }
reed@google.com3d608122011-11-21 15:16:16 +00002337
reed@google.com33535f32012-09-25 15:37:50 +00002338 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002339 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002340 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002341 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002342
senorblancoc41e7e12015-12-07 12:51:30 -08002343 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002344 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002345
reed@google.com33535f32012-09-25 15:37:50 +00002346 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002347 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002348 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002349
reed@google.com33535f32012-09-25 15:37:50 +00002350 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002351}
2352
reed41af9662015-01-05 07:49:08 -08002353void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002354 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002355 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002356 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002357 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002358}
2359
reed4c21dc52015-06-25 12:32:03 -07002360void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2361 const SkPaint* paint) {
2362 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002363
halcanary96fcdcc2015-08-27 07:41:13 -07002364 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002365 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002366 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2367 return;
2368 }
reed@google.com3d608122011-11-21 15:16:16 +00002369 }
halcanary9d524f22016-03-29 09:03:52 -07002370
reed4c21dc52015-06-25 12:32:03 -07002371 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002372 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002373 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002374 }
halcanary9d524f22016-03-29 09:03:52 -07002375
senorblancoc41e7e12015-12-07 12:51:30 -08002376 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002377
reed4c21dc52015-06-25 12:32:03 -07002378 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002379 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002380 }
halcanary9d524f22016-03-29 09:03:52 -07002381
reed4c21dc52015-06-25 12:32:03 -07002382 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002383}
2384
reed41af9662015-01-05 07:49:08 -08002385void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2386 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002387 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002388 SkDEBUGCODE(bitmap.validate();)
2389
halcanary96fcdcc2015-08-27 07:41:13 -07002390 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002391 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002392 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2393 return;
2394 }
reed4c21dc52015-06-25 12:32:03 -07002395 }
halcanary9d524f22016-03-29 09:03:52 -07002396
reed4c21dc52015-06-25 12:32:03 -07002397 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002398 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002399 paint = lazy.init();
2400 }
halcanary9d524f22016-03-29 09:03:52 -07002401
senorblancoc41e7e12015-12-07 12:51:30 -08002402 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002403
reed4c21dc52015-06-25 12:32:03 -07002404 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002405 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002406 }
halcanary9d524f22016-03-29 09:03:52 -07002407
reed4c21dc52015-06-25 12:32:03 -07002408 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002409}
2410
msarett16882062016-08-16 09:31:08 -07002411void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2412 const SkPaint* paint) {
2413 if (nullptr == paint || paint->canComputeFastBounds()) {
2414 SkRect storage;
2415 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2416 return;
2417 }
2418 }
2419
2420 SkLazyPaint lazy;
2421 if (nullptr == paint) {
2422 paint = lazy.init();
2423 }
2424
2425 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2426
2427 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002428 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002429 }
2430
2431 LOOPER_END
2432}
2433
2434void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2435 const SkRect& dst, const SkPaint* paint) {
2436 if (nullptr == paint || paint->canComputeFastBounds()) {
2437 SkRect storage;
2438 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2439 return;
2440 }
2441 }
2442
2443 SkLazyPaint lazy;
2444 if (nullptr == paint) {
2445 paint = lazy.init();
2446 }
2447
2448 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2449
2450 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002451 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002452 }
2453
2454 LOOPER_END
2455}
2456
reed@google.comf67e4cf2011-03-15 20:56:58 +00002457class SkDeviceFilteredPaint {
2458public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002459 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002460 uint32_t filteredFlags = device->filterTextFlags(paint);
2461 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002462 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002463 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002464 fPaint = newPaint;
2465 } else {
2466 fPaint = &paint;
2467 }
2468 }
2469
reed@google.comf67e4cf2011-03-15 20:56:58 +00002470 const SkPaint& paint() const { return *fPaint; }
2471
2472private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002473 const SkPaint* fPaint;
2474 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002475};
2476
reed@google.come0d9ce82014-04-23 04:00:17 +00002477void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2478 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002479 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002480
2481 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002482 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002483 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002484 }
2485
reed@google.com4e2b3d32011-04-07 14:18:59 +00002486 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002487}
2488
reed@google.come0d9ce82014-04-23 04:00:17 +00002489void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2490 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002491 SkPoint textOffset = SkPoint::Make(0, 0);
2492
halcanary96fcdcc2015-08-27 07:41:13 -07002493 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002494
reed@android.com8a1c16f2008-12-17 15:59:43 +00002495 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002496 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002497 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002498 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002499 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002500
reed@google.com4e2b3d32011-04-07 14:18:59 +00002501 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002502}
2503
reed@google.come0d9ce82014-04-23 04:00:17 +00002504void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2505 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002506
2507 SkPoint textOffset = SkPoint::Make(0, constY);
2508
halcanary96fcdcc2015-08-27 07:41:13 -07002509 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002510
reed@android.com8a1c16f2008-12-17 15:59:43 +00002511 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002512 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002513 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002514 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002515 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002516
reed@google.com4e2b3d32011-04-07 14:18:59 +00002517 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002518}
2519
reed@google.come0d9ce82014-04-23 04:00:17 +00002520void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2521 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002522 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002523
reed@android.com8a1c16f2008-12-17 15:59:43 +00002524 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002525 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002526 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002527 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002528
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002529 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002530}
2531
reed45561a02016-07-07 12:47:17 -07002532void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2533 const SkRect* cullRect, const SkPaint& paint) {
2534 if (cullRect && this->quickReject(*cullRect)) {
2535 return;
2536 }
2537
2538 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2539
2540 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002541 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002542 }
2543
2544 LOOPER_END
2545}
2546
fmalita00d5c2c2014-08-21 08:53:26 -07002547void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2548 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002549
fmalita85d5eb92015-03-04 11:20:12 -08002550 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002551 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002552 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002553 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002554 SkRect tmp;
2555 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2556 return;
2557 }
2558 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002559 }
2560
fmalita024f9962015-03-03 19:08:17 -08002561 // We cannot filter in the looper as we normally do, because the paint is
2562 // incomplete at this point (text-related attributes are embedded within blob run paints).
2563 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002564 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002565
fmalita85d5eb92015-03-04 11:20:12 -08002566 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002567
fmalitaaa1b9122014-08-28 14:32:24 -07002568 while (iter.next()) {
2569 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002570 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002571 }
2572
fmalitaaa1b9122014-08-28 14:32:24 -07002573 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002574
2575 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002576}
2577
Cary Clark2a475ea2017-04-28 15:35:12 -04002578void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2579 this->drawText(string.c_str(), string.size(), x, y, paint);
2580}
2581
reed@google.come0d9ce82014-04-23 04:00:17 +00002582// These will become non-virtual, so they always call the (virtual) onDraw... method
2583void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2584 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002585 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002586 if (byteLength) {
2587 this->onDrawText(text, byteLength, x, y, paint);
2588 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002589}
2590void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2591 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002592 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002593 if (byteLength) {
2594 this->onDrawPosText(text, byteLength, pos, paint);
2595 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002596}
2597void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2598 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002599 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002600 if (byteLength) {
2601 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2602 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002603}
2604void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2605 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002606 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002607 if (byteLength) {
2608 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2609 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002610}
reed45561a02016-07-07 12:47:17 -07002611void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2612 const SkRect* cullRect, const SkPaint& paint) {
2613 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2614 if (byteLength) {
2615 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2616 }
2617}
fmalita00d5c2c2014-08-21 08:53:26 -07002618void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2619 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002620 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002621 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002622 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002623}
reed@google.come0d9ce82014-04-23 04:00:17 +00002624
Mike Reede88a1cb2017-03-17 09:50:46 -04002625void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2626 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002627 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2628 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2629
2630 while (iter.next()) {
2631 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002632 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002633 }
2634
2635 LOOPER_END
2636}
2637
dandovb3c9d1c2014-08-12 08:34:29 -07002638void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002639 const SkPoint texCoords[4], SkBlendMode bmode,
2640 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002641 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002642 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002643 return;
2644 }
mtklein6cfa73a2014-08-13 13:33:49 -07002645
Mike Reedfaba3712016-11-03 14:45:31 -04002646 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002647}
2648
2649void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002650 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002651 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002652 // Since a patch is always within the convex hull of the control points, we discard it when its
2653 // bounding rectangle is completely outside the current clip.
2654 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002655 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002656 if (this->quickReject(bounds)) {
2657 return;
2658 }
mtklein6cfa73a2014-08-13 13:33:49 -07002659
halcanary96fcdcc2015-08-27 07:41:13 -07002660 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002661
dandovecfff212014-08-04 10:02:00 -07002662 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002663 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002664 }
mtklein6cfa73a2014-08-13 13:33:49 -07002665
dandovecfff212014-08-04 10:02:00 -07002666 LOOPER_END
2667}
2668
reeda8db7282015-07-07 10:22:31 -07002669void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002670 RETURN_ON_NULL(dr);
2671 if (x || y) {
2672 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2673 this->onDrawDrawable(dr, &matrix);
2674 } else {
2675 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002676 }
2677}
2678
reeda8db7282015-07-07 10:22:31 -07002679void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002680 RETURN_ON_NULL(dr);
2681 if (matrix && matrix->isIdentity()) {
2682 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002683 }
reede3b38ce2016-01-08 09:18:44 -08002684 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002685}
2686
2687void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002688 // drawable bounds are no longer reliable (e.g. android displaylist)
2689 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002690 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002691}
2692
reed71c3c762015-06-24 10:29:17 -07002693void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002694 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002695 const SkRect* cull, const SkPaint* paint) {
2696 if (cull && this->quickReject(*cull)) {
2697 return;
2698 }
2699
2700 SkPaint pnt;
2701 if (paint) {
2702 pnt = *paint;
2703 }
halcanary9d524f22016-03-29 09:03:52 -07002704
halcanary96fcdcc2015-08-27 07:41:13 -07002705 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002706 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002707 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002708 }
2709 LOOPER_END
2710}
2711
reedf70b5312016-03-04 16:36:20 -08002712void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2713 SkASSERT(key);
2714
2715 SkPaint paint;
2716 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2717 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002718 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002719 }
2720 LOOPER_END
2721}
2722
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723//////////////////////////////////////////////////////////////////////////////
2724// These methods are NOT virtual, and therefore must call back into virtual
2725// methods, rather than actually drawing themselves.
2726//////////////////////////////////////////////////////////////////////////////
2727
reed374772b2016-10-05 17:33:02 -07002728void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002729 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730 SkPaint paint;
2731
2732 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002733 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002734 this->drawPaint(paint);
2735}
2736
2737void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002738 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002739 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002740 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2741}
2742
Mike Reed3661bc92017-02-22 13:21:42 -05002743void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002744 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002745 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002746
reed@android.com8a1c16f2008-12-17 15:59:43 +00002747 pts[0].set(x0, y0);
2748 pts[1].set(x1, y1);
2749 this->drawPoints(kLines_PointMode, 2, pts, paint);
2750}
2751
Mike Reed3661bc92017-02-22 13:21:42 -05002752void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002753 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002754 if (radius < 0) {
2755 radius = 0;
2756 }
2757
2758 SkRect r;
2759 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002760 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002761}
2762
2763void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2764 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002765 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002767 SkRRect rrect;
2768 rrect.setRectXY(r, rx, ry);
2769 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770 } else {
2771 this->drawRect(r, paint);
2772 }
2773}
2774
reed@android.com8a1c16f2008-12-17 15:59:43 +00002775void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2776 SkScalar sweepAngle, bool useCenter,
2777 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002778 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002779 if (oval.isEmpty() || !sweepAngle) {
2780 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 }
bsalomon21af9ca2016-08-25 12:29:23 -07002782 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002783}
2784
2785void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2786 const SkPath& path, SkScalar hOffset,
2787 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002788 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002789 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002790
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791 matrix.setTranslate(hOffset, vOffset);
2792 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2793}
2794
reed@android.comf76bacf2009-05-13 14:00:33 +00002795///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002796
2797/**
2798 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2799 * against the playback cost of recursing into the subpicture to get at its actual ops.
2800 *
2801 * For now we pick a conservatively small value, though measurement (and other heuristics like
2802 * the type of ops contained) may justify changing this value.
2803 */
2804#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002805
reedd5fa1a42014-08-09 11:08:05 -07002806void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002807 RETURN_ON_NULL(picture);
2808
reed1c2c4412015-04-30 13:09:24 -07002809 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002810 if (matrix && matrix->isIdentity()) {
2811 matrix = nullptr;
2812 }
2813 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2814 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2815 picture->playback(this);
2816 } else {
2817 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002818 }
2819}
robertphillips9b14f262014-06-04 05:40:44 -07002820
reedd5fa1a42014-08-09 11:08:05 -07002821void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2822 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002823 if (!paint || paint->canComputeFastBounds()) {
2824 SkRect bounds = picture->cullRect();
2825 if (paint) {
2826 paint->computeFastBounds(bounds, &bounds);
2827 }
2828 if (matrix) {
2829 matrix->mapRect(&bounds);
2830 }
2831 if (this->quickReject(bounds)) {
2832 return;
2833 }
2834 }
2835
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002836 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002837 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002838}
2839
vjiaoblack95302da2016-07-21 10:25:54 -07002840#ifdef SK_EXPERIMENTAL_SHADOWING
2841void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2842 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002843 const SkPaint* paint,
2844 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002845 RETURN_ON_NULL(picture);
2846
2847 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2848
vjiaoblacke6f5d562016-08-25 06:30:23 -07002849 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002850}
2851
2852void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2853 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002854 const SkPaint* paint,
2855 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002856 if (!paint || paint->canComputeFastBounds()) {
2857 SkRect bounds = picture->cullRect();
2858 if (paint) {
2859 paint->computeFastBounds(bounds, &bounds);
2860 }
2861 if (matrix) {
2862 matrix->mapRect(&bounds);
2863 }
2864 if (this->quickReject(bounds)) {
2865 return;
2866 }
2867 }
2868
2869 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2870
vjiaoblacke6f5d562016-08-25 06:30:23 -07002871 sk_sp<SkImage> povDepthMap;
2872 sk_sp<SkImage> diffuseMap;
2873
vjiaoblack904527d2016-08-09 09:32:09 -07002874 // povDepthMap
2875 {
2876 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002877 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2878 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002879 sk_sp<SkLights> povLight = builder.finish();
2880
2881 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2882 picture->cullRect().height(),
2883 kBGRA_8888_SkColorType,
2884 kOpaque_SkAlphaType);
2885
2886 // Create a new surface (that matches the backend of canvas)
2887 // to create the povDepthMap
2888 sk_sp<SkSurface> surf(this->makeSurface(info));
2889
2890 // Wrap another SPFCanvas around the surface
2891 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2892 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2893
2894 // set the depth map canvas to have the light as the user's POV
2895 depthMapCanvas->setLights(std::move(povLight));
2896
2897 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002898 povDepthMap = surf->makeImageSnapshot();
2899 }
2900
2901 // diffuseMap
2902 {
2903 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2904 picture->cullRect().height(),
2905 kBGRA_8888_SkColorType,
2906 kOpaque_SkAlphaType);
2907
2908 sk_sp<SkSurface> surf(this->makeSurface(info));
2909 surf->getCanvas()->drawPicture(picture);
2910
2911 diffuseMap = surf->makeImageSnapshot();
2912 }
vjiaoblack904527d2016-08-09 09:32:09 -07002913
Mike Reed0acd7952017-04-28 11:12:19 -04002914 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader();
2915 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader();
vjiaoblackb2796fd2016-09-09 09:22:39 -07002916
2917 // TODO: pass the depth to the shader in vertices, or uniforms
2918 // so we don't have to render depth and color separately
2919 for (int i = 0; i < fLights->numLights(); ++i) {
2920 // skip over ambient lights; they don't cast shadows
2921 // lights that have shadow maps do not need updating (because lights are immutable)
2922 sk_sp<SkImage> depthMap;
2923 SkISize shMapSize;
2924
2925 if (fLights->light(i).getShadowMap() != nullptr) {
2926 continue;
2927 }
2928
2929 if (fLights->light(i).isRadial()) {
2930 shMapSize.fHeight = 1;
2931 shMapSize.fWidth = (int) picture->cullRect().width();
2932
2933 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
2934 kBGRA_8888_SkColorType,
2935 kOpaque_SkAlphaType);
2936
2937 // Create new surface (that matches the backend of canvas)
2938 // for each shadow map
2939 sk_sp<SkSurface> surf(this->makeSurface(info));
2940
2941 // Wrap another SPFCanvas around the surface
2942 SkCanvas* depthMapCanvas = surf->getCanvas();
2943
2944 SkLights::Builder builder;
2945 builder.add(fLights->light(i));
2946 sk_sp<SkLights> curLight = builder.finish();
2947
2948 sk_sp<SkShader> shadowMapShader;
2949 shadowMapShader = SkRadialShadowMapShader::Make(
2950 povDepthShader, curLight,
2951 (int) picture->cullRect().width(),
2952 (int) picture->cullRect().height());
2953
2954 SkPaint shadowMapPaint;
2955 shadowMapPaint.setShader(std::move(shadowMapShader));
2956
2957 depthMapCanvas->setLights(curLight);
2958
2959 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
2960 diffuseMap->height()),
2961 shadowMapPaint);
2962
2963 depthMap = surf->makeImageSnapshot();
2964
2965 } else {
2966 // TODO: compute the correct size of the depth map from the light properties
2967 // TODO: maybe add a kDepth_8_SkColorType
2968 // TODO: find actual max depth of picture
2969 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
2970 fLights->light(i), 255,
2971 (int) picture->cullRect().width(),
2972 (int) picture->cullRect().height());
2973
2974 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
2975 kBGRA_8888_SkColorType,
2976 kOpaque_SkAlphaType);
2977
2978 // Create a new surface (that matches the backend of canvas)
2979 // for each shadow map
2980 sk_sp<SkSurface> surf(this->makeSurface(info));
2981
2982 // Wrap another SPFCanvas around the surface
2983 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2984 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2985 depthMapCanvas->setShadowParams(params);
2986
2987 // set the depth map canvas to have the light we're drawing.
2988 SkLights::Builder builder;
2989 builder.add(fLights->light(i));
2990 sk_sp<SkLights> curLight = builder.finish();
2991 depthMapCanvas->setLights(std::move(curLight));
2992
2993 depthMapCanvas->drawPicture(picture);
2994 depthMap = surf->makeImageSnapshot();
2995 }
2996
2997 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
2998 fLights->light(i).setShadowMap(std::move(depthMap));
2999 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3000 // we blur the variance map
3001 SkPaint blurPaint;
3002 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3003 params.fShadowRadius, nullptr));
3004
3005 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3006 kBGRA_8888_SkColorType,
3007 kOpaque_SkAlphaType);
3008
3009 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3010
3011 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3012
3013 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3014 }
3015 }
3016
3017 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003018 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3019 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003020 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003021 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003022 diffuseMap->height(),
3023 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003024
3025 shadowPaint.setShader(shadowShader);
3026
3027 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003028}
3029#endif
3030
reed@android.com8a1c16f2008-12-17 15:59:43 +00003031///////////////////////////////////////////////////////////////////////////////
3032///////////////////////////////////////////////////////////////////////////////
3033
reed3aafe112016-08-18 12:45:34 -07003034SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003035 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003036
3037 SkASSERT(canvas);
3038
reed3aafe112016-08-18 12:45:34 -07003039 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003040 fDone = !fImpl->next();
3041}
3042
3043SkCanvas::LayerIter::~LayerIter() {
3044 fImpl->~SkDrawIter();
3045}
3046
3047void SkCanvas::LayerIter::next() {
3048 fDone = !fImpl->next();
3049}
3050
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003051SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003052 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003053}
3054
3055const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003056 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003057}
3058
3059const SkPaint& SkCanvas::LayerIter::paint() const {
3060 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003061 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003062 paint = &fDefaultPaint;
3063 }
3064 return *paint;
3065}
3066
Mike Reeda1361362017-03-07 09:37:29 -05003067void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3068 return fImpl->fDevice->onAsRgnClip(rgn);
3069}
3070
reed@android.com8a1c16f2008-12-17 15:59:43 +00003071int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3072int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003073
3074///////////////////////////////////////////////////////////////////////////////
3075
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003076static bool supported_for_raster_canvas(const SkImageInfo& info) {
3077 switch (info.alphaType()) {
3078 case kPremul_SkAlphaType:
3079 case kOpaque_SkAlphaType:
3080 break;
3081 default:
3082 return false;
3083 }
3084
3085 switch (info.colorType()) {
3086 case kAlpha_8_SkColorType:
3087 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003088 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003089 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003090 break;
3091 default:
3092 return false;
3093 }
3094
3095 return true;
3096}
3097
Mike Reed5df49342016-11-12 08:06:55 -06003098std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3099 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003100 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003101 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003102 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003103
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003104 SkBitmap bitmap;
3105 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003106 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003107 }
Mike Reed5df49342016-11-12 08:06:55 -06003108 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003109}
reedd5fa1a42014-08-09 11:08:05 -07003110
3111///////////////////////////////////////////////////////////////////////////////
3112
3113SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003114 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003115 : fCanvas(canvas)
3116 , fSaveCount(canvas->getSaveCount())
3117{
bsalomon49f085d2014-09-05 13:34:00 -07003118 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003119 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003120 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003121 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003122 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003123 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003124 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003125 canvas->save();
3126 }
mtklein6cfa73a2014-08-13 13:33:49 -07003127
bsalomon49f085d2014-09-05 13:34:00 -07003128 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003129 canvas->concat(*matrix);
3130 }
3131}
3132
3133SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3134 fCanvas->restoreToCount(fSaveCount);
3135}
reede8f30622016-03-23 18:59:25 -07003136
Florin Malitaee424ac2016-12-01 12:47:59 -05003137///////////////////////////////////////////////////////////////////////////////
3138
3139SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3140 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3141
Florin Malita439ace92016-12-02 12:05:41 -05003142SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3143 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3144
Florin Malitaee424ac2016-12-01 12:47:59 -05003145SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3146 (void)this->INHERITED::getSaveLayerStrategy(rec);
3147 return kNoLayer_SaveLayerStrategy;
3148}
3149
3150///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003151
reed73603f32016-09-20 08:42:38 -07003152static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3153static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3154static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3155static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3156static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3157static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003158
3159///////////////////////////////////////////////////////////////////////////////////////////////////
3160
3161SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3162 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04003163 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05003164 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3165 SkIPoint origin = dev->getOrigin();
3166 SkMatrix ctm = this->getTotalMatrix();
3167 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3168
3169 SkIRect clip = fMCRec->fRasterClip.getBounds();
3170 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003171 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003172 clip.setEmpty();
3173 }
3174
3175 fAllocator->updateHandle(handle, ctm, clip);
3176 return handle;
3177 }
3178 return nullptr;
3179}
3180
3181static bool install(SkBitmap* bm, const SkImageInfo& info,
3182 const SkRasterHandleAllocator::Rec& rec) {
3183 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3184 rec.fReleaseProc, rec.fReleaseCtx);
3185}
3186
3187SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3188 SkBitmap* bm) {
3189 SkRasterHandleAllocator::Rec rec;
3190 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3191 return nullptr;
3192 }
3193 return rec.fHandle;
3194}
3195
3196std::unique_ptr<SkCanvas>
3197SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3198 const SkImageInfo& info, const Rec* rec) {
3199 if (!alloc || !supported_for_raster_canvas(info)) {
3200 return nullptr;
3201 }
3202
3203 SkBitmap bm;
3204 Handle hndl;
3205
3206 if (rec) {
3207 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3208 } else {
3209 hndl = alloc->allocBitmap(info, &bm);
3210 }
3211 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3212}