blob: 5f342c4082759de1911337316c19daff1bf0f11e [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
Hal Canaryc640d0d2018-06-13 09:59:02 -04008#include "SkCanvas.h"
9
Herb Derby73fe7b02017-02-08 15:12:19 -050010#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +000011#include "SkBitmapDevice.h"
reedd5fa1a42014-08-09 11:08:05 -070012#include "SkCanvasPriv.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040013#include "SkClipOpPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070014#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070015#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDraw.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#include "SkDrawLooper.h"
Herb Derby41f4f312018-06-06 17:45:53 +000018#include "SkGlyphRun.h"
piotaixrb5fae932014-09-24 13:03:30 -070019#include "SkImage.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040022#include "SkImage_Base.h"
msarettc573a402016-08-02 08:05:56 -070023#include "SkLatticeIter.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040024#include "SkMSAN.h"
Mike Reed5df49342016-11-12 08:06:55 -060025#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080026#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000027#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050028#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070029#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070030#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070031#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040032#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000033#include "SkPicture.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040034#include "SkRRect.h"
reed@google.com00177082011-10-12 14:34:30 +000035#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050036#include "SkRasterHandleAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080037#include "SkSpecialImage.h"
Herb Derby41f4f312018-06-06 17:45:53 +000038#include "SkStrikeCache.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040039#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000040#include "SkSurface_Base.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040041#include "SkTLazy.h"
fmalita7ba7aa72014-08-29 09:46:36 -070042#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000043#include "SkTextFormatParams.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040044#include "SkTo.h"
danakj8f757f52014-11-04 11:48:43 -080045#include "SkTraceEvent.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040046#include "SkVertices.h"
47
bungemand3ebb482015-08-05 13:57:49 -070048#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080051#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050052#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053#endif
54
reede3b38ce2016-01-08 09:18:44 -080055#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050056#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080057
Mike Reed139e5e02017-03-08 11:29:33 -050058///////////////////////////////////////////////////////////////////////////////////////////////////
59
reedc83a2972015-07-16 07:40:45 -070060/*
61 * Return true if the drawing this rect would hit every pixels in the canvas.
62 *
63 * Returns false if
64 * - rect does not contain the canvas' bounds
65 * - paint is not fill
66 * - paint would blur or otherwise change the coverage of the rect
67 */
68bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
69 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070070 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
71 (int)kNone_ShaderOverrideOpacity,
72 "need_matching_enums0");
73 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
74 (int)kOpaque_ShaderOverrideOpacity,
75 "need_matching_enums1");
76 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
77 (int)kNotOpaque_ShaderOverrideOpacity,
78 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070079
80 const SkISize size = this->getBaseLayerSize();
81 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050082
83 // if we're clipped at all, we can't overwrite the entire surface
84 {
85 SkBaseDevice* base = this->getDevice();
86 SkBaseDevice* top = this->getTopDevice();
87 if (base != top) {
88 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
89 }
90 if (!base->clipIsWideOpen()) {
91 return false;
92 }
reedc83a2972015-07-16 07:40:45 -070093 }
94
95 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070096 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070097 return false; // conservative
98 }
halcanaryc5769b22016-08-10 07:13:21 -070099
100 SkRect devRect;
101 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
102 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700103 return false;
104 }
105 }
106
107 if (paint) {
108 SkPaint::Style paintStyle = paint->getStyle();
109 if (!(paintStyle == SkPaint::kFill_Style ||
110 paintStyle == SkPaint::kStrokeAndFill_Style)) {
111 return false;
112 }
113 if (paint->getMaskFilter() || paint->getLooper()
114 || paint->getPathEffect() || paint->getImageFilter()) {
115 return false; // conservative
116 }
117 }
118 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
119}
120
121///////////////////////////////////////////////////////////////////////////////////////////////////
122
reed@google.comda17f752012-08-16 18:27:05 +0000123// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124//#define SK_TRACE_SAVERESTORE
125
126#ifdef SK_TRACE_SAVERESTORE
127 static int gLayerCounter;
128 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
129 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
130
131 static int gRecCounter;
132 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
133 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
134
135 static int gCanvasCounter;
136 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
137 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
138#else
139 #define inc_layer()
140 #define dec_layer()
141 #define inc_rec()
142 #define dec_rec()
143 #define inc_canvas()
144 #define dec_canvas()
145#endif
146
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000147typedef SkTLazy<SkPaint> SkLazyPaint;
148
reedc83a2972015-07-16 07:40:45 -0700149void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000150 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700151 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
152 ? SkSurface::kDiscard_ContentChangeMode
153 : SkSurface::kRetain_ContentChangeMode);
154 }
155}
156
157void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
158 ShaderOverrideOpacity overrideOpacity) {
159 if (fSurfaceBase) {
160 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
161 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
162 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
163 // and therefore we don't care which mode we're in.
164 //
165 if (fSurfaceBase->outstandingImageSnapshot()) {
166 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
167 mode = SkSurface::kDiscard_ContentChangeMode;
168 }
169 }
170 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000171 }
172}
173
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000176/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 The clip/matrix/proc are fields that reflect the top of the save/restore
178 stack. Whenever the canvas changes, it marks a dirty flag, and then before
179 these are used (assuming we're not on a layer) we rebuild these cache
180 values: they reflect the top of the save stack, but translated and clipped
181 by the device's XY offset and bitmap-bounds.
182*/
183struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400184 DeviceCM* fNext;
185 sk_sp<SkBaseDevice> fDevice;
186 SkRasterClip fClip;
187 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
188 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400189 sk_sp<SkImage> fClipImage;
190 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191
Florin Malita53f77bd2017-04-28 13:48:37 -0400192 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000193 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700194 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400195 , fDevice(std::move(device))
196 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700197 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000198 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400199 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400200 {}
reed@google.com4b226022011-01-11 18:32:13 +0000201
mtkleinfeaadee2015-04-08 11:25:48 -0700202 void reset(const SkIRect& bounds) {
203 SkASSERT(!fPaint);
204 SkASSERT(!fNext);
205 SkASSERT(fDevice);
206 fClip.setRect(bounds);
207 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208};
209
Mike Reed148b7fd2018-12-18 17:38:18 -0500210namespace {
211// Encapsulate state needed to restore from saveBehind()
212struct BackImage {
213 sk_sp<SkSpecialImage> fImage;
214 SkIPoint fLoc;
215};
216}
217
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218/* This is the record we keep for each save/restore level in the stack.
219 Since a level optionally copies the matrix and/or stack, we have pointers
220 for these fields. If the value is copied for this level, the copy is
221 stored in the ...Storage field, and the pointer points to that. If the
222 value is not copied for this level, we ignore ...Storage, and just point
223 at the corresponding value in the previous level in the stack.
224*/
225class SkCanvas::MCRec {
226public:
Mike Reed148b7fd2018-12-18 17:38:18 -0500227 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228 /* If there are any layers in the stack, this points to the top-most
229 one that is at or below this level in the stack (so we know what
230 bitmap/device to draw into from this level. This value is NOT
231 reference counted, since the real owner is either our fLayer field,
232 or a previous one in a lower level.)
233 */
Mike Reed148b7fd2018-12-18 17:38:18 -0500234 DeviceCM* fTopLayer;
235 std::unique_ptr<BackImage> fBackImage;
236 SkConservativeClip fRasterClip;
237 SkMatrix fMatrix;
238 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239
Mike Reeda1361362017-03-07 09:37:29 -0500240 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700241 fLayer = nullptr;
242 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800243 fMatrix.reset();
244 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700245
reedd9544982014-09-09 18:46:22 -0700246 // don't bother initializing fNext
247 inc_rec();
248 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400249 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700250 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700251 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800252 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700253
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 // don't bother initializing fNext
255 inc_rec();
256 }
257 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700258 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259 dec_rec();
260 }
mtkleinfeaadee2015-04-08 11:25:48 -0700261
262 void reset(const SkIRect& bounds) {
263 SkASSERT(fLayer);
264 SkASSERT(fDeferredSaveCount == 0);
265
266 fMatrix.reset();
267 fRasterClip.setRect(bounds);
268 fLayer->reset(bounds);
269 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270};
271
Mike Reeda1361362017-03-07 09:37:29 -0500272class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273public:
Mike Reeda1361362017-03-07 09:37:29 -0500274 SkDrawIter(SkCanvas* canvas)
275 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
276 {}
reed@google.com4b226022011-01-11 18:32:13 +0000277
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000279 const DeviceCM* rec = fCurrLayer;
280 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400281 fDevice = rec->fDevice.get();
282 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700284 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 return true;
286 }
287 return false;
288 }
reed@google.com4b226022011-01-11 18:32:13 +0000289
reed@google.com6f8f2922011-03-04 22:27:10 +0000290 int getX() const { return fDevice->getOrigin().x(); }
291 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000293
Mike Reed99330ba2017-02-22 11:01:08 -0500294 SkBaseDevice* fDevice;
295
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 const DeviceCM* fCurrLayer;
298 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299};
300
Florin Malita713b8ef2017-04-28 10:57:24 -0400301#define FOR_EACH_TOP_DEVICE( code ) \
302 do { \
303 DeviceCM* layer = fMCRec->fTopLayer; \
304 while (layer) { \
305 SkBaseDevice* device = layer->fDevice.get(); \
306 if (device) { \
307 code; \
308 } \
309 layer = layer->fNext; \
310 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500311 } while (0)
312
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313/////////////////////////////////////////////////////////////////////////////
314
reeddbc3cef2015-04-29 12:18:57 -0700315static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
316 return lazy->isValid() ? lazy->get() : lazy->set(orig);
317}
318
319/**
320 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700321 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700322 */
reedd053ce92016-03-22 10:17:23 -0700323static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700324 SkImageFilter* imgf = paint.getImageFilter();
325 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700326 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700327 }
328
reedd053ce92016-03-22 10:17:23 -0700329 SkColorFilter* imgCFPtr;
330 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700331 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700332 }
reedd053ce92016-03-22 10:17:23 -0700333 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700334
335 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700336 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700337 // there is no existing paint colorfilter, so we can just return the imagefilter's
338 return imgCF;
339 }
340
341 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
342 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500343 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700344}
345
senorblanco87e066e2015-10-28 11:23:36 -0700346/**
347 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
348 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
349 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
350 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
351 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
352 * conservative "effective" bounds based on the settings in the paint... with one exception. This
353 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
354 * deliberately ignored.
355 */
356static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
357 const SkRect& rawBounds,
358 SkRect* storage) {
359 SkPaint tmpUnfiltered(paint);
360 tmpUnfiltered.setImageFilter(nullptr);
361 if (tmpUnfiltered.canComputeFastBounds()) {
362 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
363 } else {
364 return rawBounds;
365 }
366}
367
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368class AutoDrawLooper {
369public:
senorblanco87e066e2015-10-28 11:23:36 -0700370 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
371 // paint. It's used to determine the size of the offscreen layer for filters.
372 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700373 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700374 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000375 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700376 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000377 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700378 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000379 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380
reedd053ce92016-03-22 10:17:23 -0700381 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700382 if (simplifiedCF) {
383 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700384 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700385 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700386 fPaint = paint;
387 }
388
389 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700390 /**
391 * We implement ImageFilters for a given draw by creating a layer, then applying the
392 * imagefilter to the pixels of that layer (its backing surface/image), and then
393 * we call restore() to xfer that layer to the main canvas.
394 *
395 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
396 * 2. Generate the src pixels:
397 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
398 * return (fPaint). We then draw the primitive (using srcover) into a cleared
399 * buffer/surface.
400 * 3. Restore the layer created in #1
401 * The imagefilter is passed the buffer/surface from the layer (now filled with the
402 * src pixels of the primitive). It returns a new "filtered" buffer, which we
403 * draw onto the previous layer using the xfermode from the original paint.
404 */
reed@google.com8926b162012-03-23 15:36:36 +0000405 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500406 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700407 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700408 SkRect storage;
409 if (rawBounds) {
410 // Make rawBounds include all paint outsets except for those due to image filters.
411 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
412 }
reedbfd5f172016-01-07 11:28:08 -0800413 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700414 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700415 fTempLayerForImageFilter = true;
416 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000417 }
418
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000419 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500420 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000421 fIsSimple = false;
422 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700423 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000424 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400425 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000426 }
427 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000428
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700430 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000431 fCanvas->internalRestore();
432 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000433 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000435
reed@google.com4e2b3d32011-04-07 14:18:59 +0000436 const SkPaint& paint() const {
437 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400438 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000439 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000441
Ben Wagner2c312c42018-06-27 14:46:46 -0400442 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000443 if (fDone) {
444 return false;
445 } else if (fIsSimple) {
446 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000447 return !fPaint->nothingToDraw();
448 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400449 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000450 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000451 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000452
reed@android.com8a1c16f2008-12-17 15:59:43 +0000453private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500454 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700455 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000456 SkCanvas* fCanvas;
457 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000458 const SkPaint* fPaint;
459 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700460 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000461 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000462 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000463 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400464 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000465
Ben Wagner2c312c42018-06-27 14:46:46 -0400466 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000467};
468
Ben Wagner2c312c42018-06-27 14:46:46 -0400469bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700470 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000471 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400472 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000473
reeddbc3cef2015-04-29 12:18:57 -0700474 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
475 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400476 // never want our downstream clients (i.e. devices) to see loopers
477 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000478
reed5c476fb2015-04-20 08:04:21 -0700479 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700480 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700481 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000482 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000483
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000484 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000485 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000486 return false;
487 }
reed@google.com129ec222012-05-15 13:24:09 +0000488 fPaint = paint;
489
490 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400491 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000492 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000493 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000494 return true;
495}
496
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497////////// macros to place around the internal draw calls //////////////////
498
reed3aafe112016-08-18 12:45:34 -0700499#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
500 this->predrawNotify(); \
501 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400502 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800503 SkDrawIter iter(this);
504
505
Ben Wagner2c312c42018-06-27 14:46:46 -0400506#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000507 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700508 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400509 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000510 SkDrawIter iter(this);
511
Ben Wagner2c312c42018-06-27 14:46:46 -0400512#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000513 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700514 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400515 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000517
Ben Wagner2c312c42018-06-27 14:46:46 -0400518#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700519 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700520 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400521 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700522 SkDrawIter iter(this);
523
reed@google.com4e2b3d32011-04-07 14:18:59 +0000524#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525
526////////////////////////////////////////////////////////////////////////////
527
msarettfbfa2582016-08-12 08:29:08 -0700528static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
529 if (bounds.isEmpty()) {
530 return SkRect::MakeEmpty();
531 }
532
533 // Expand bounds out by 1 in case we are anti-aliasing. We store the
534 // bounds as floats to enable a faster quick reject implementation.
535 SkRect dst;
536 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
537 return dst;
538}
539
mtkleinfeaadee2015-04-08 11:25:48 -0700540void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
541 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700542 fMCRec->reset(bounds);
543
544 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500545 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400546 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700547 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700548 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700549}
550
Hal Canary363a3f82018-10-04 11:04:48 -0400551void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000552 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800553 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700554 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555
556 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500557 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500558 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700559 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000560
reeda499f902015-05-01 09:34:31 -0700561 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
562 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400563 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700564
reed@android.com8a1c16f2008-12-17 15:59:43 +0000565 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000566
halcanary96fcdcc2015-08-27 07:41:13 -0700567 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000568
reedf92c8662014-08-18 08:02:43 -0700569 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700570 // The root device and the canvas should always have the same pixel geometry
571 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800572 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700573 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500574
Mike Reedc42a1cd2017-02-14 14:25:14 -0500575 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700576 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400577
Herb Derby59d997a2018-06-07 12:44:09 -0400578 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000579}
580
reed@google.comcde92112011-07-06 20:00:52 +0000581SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000582 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700583 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000584{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000585 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000586
Hal Canary363a3f82018-10-04 11:04:48 -0400587 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000588}
589
reed96a857e2015-01-25 10:33:58 -0800590SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000591 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800592 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000593{
594 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400595 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400596 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700597}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000598
Hal Canary363a3f82018-10-04 11:04:48 -0400599SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700600 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700601 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700602{
603 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700604
Mike Reed566e53c2017-03-10 10:49:45 -0500605 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400606 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700607}
608
Herb Derbyefe39bc2018-05-01 17:06:20 -0400609SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000610 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700611 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000612{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000613 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700614
Hal Canary363a3f82018-10-04 11:04:48 -0400615 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700616}
617
reed4a8126e2014-09-22 07:29:03 -0700618SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700619 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700620 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700621{
622 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700623
Mike Reed910ca0f2018-04-25 13:04:05 -0400624 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400625 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700626}
reed29c857d2014-09-21 10:25:07 -0700627
Mike Reed356f7c22017-01-10 11:58:39 -0500628SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
629 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700630 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
631 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500632 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700633{
634 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700635
Mike Reed910ca0f2018-04-25 13:04:05 -0400636 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400637 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638}
639
Mike Reed356f7c22017-01-10 11:58:39 -0500640SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
641
Matt Sarett31f99ce2017-04-11 08:46:01 -0400642#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
643SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
644 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
645 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
646 , fAllocator(nullptr)
647{
648 inc_canvas();
649
650 SkBitmap tmp(bitmap);
651 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400652 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400653 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400654}
655#endif
656
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657SkCanvas::~SkCanvas() {
658 // free up the contents of our deque
659 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000660
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661 this->internalRestore(); // restore the last, since we're going away
662
halcanary385fe4d2015-08-26 13:07:48 -0700663 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000664
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665 dec_canvas();
666}
667
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000668SkMetaData& SkCanvas::getMetaData() {
669 // metadata users are rare, so we lazily allocate it. If that changes we
670 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700671 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000672 fMetaData = new SkMetaData;
673 }
674 return *fMetaData;
675}
676
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677///////////////////////////////////////////////////////////////////////////////
678
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000679void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700680 this->onFlush();
681}
682
683void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000684 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000685 if (device) {
686 device->flush();
687 }
688}
689
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000690SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000691 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000692 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
693}
694
senorblancoafc7cce2016-02-02 18:44:15 -0800695SkIRect SkCanvas::getTopLayerBounds() const {
696 SkBaseDevice* d = this->getTopDevice();
697 if (!d) {
698 return SkIRect::MakeEmpty();
699 }
700 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
701}
702
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000703SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000704 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000705 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000706 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400707 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000708}
709
Florin Malita0ed3b642017-01-13 16:56:38 +0000710SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400711 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000712}
713
Mike Reed353196f2017-07-21 11:01:18 -0400714bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000715 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400716 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000717}
718
Mike Reed353196f2017-07-21 11:01:18 -0400719bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
720 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400721}
722
723bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
724 SkPixmap pm;
725 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
726}
727
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000728bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400729 SkPixmap pm;
730 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700731 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000732 }
733 return false;
734}
735
Matt Sarett03dd6d52017-01-23 12:15:09 -0500736bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000737 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000738 SkBaseDevice* device = this->getDevice();
739 if (!device) {
740 return false;
741 }
742
Matt Sarett03dd6d52017-01-23 12:15:09 -0500743 // This check gives us an early out and prevents generation ID churn on the surface.
744 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
745 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
746 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
747 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000748 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000749
Matt Sarett03dd6d52017-01-23 12:15:09 -0500750 // Tell our owning surface to bump its generation ID.
751 const bool completeOverwrite =
752 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700753 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700754
Matt Sarett03dd6d52017-01-23 12:15:09 -0500755 // This can still fail, most notably in the case of a invalid color type or alpha type
756 // conversion. We could pull those checks into this function and avoid the unnecessary
757 // generation ID bump. But then we would be performing those checks twice, since they
758 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400759 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000760}
reed@google.com51df9e32010-12-23 19:29:18 +0000761
reed@android.com8a1c16f2008-12-17 15:59:43 +0000762//////////////////////////////////////////////////////////////////////////////
763
reed2ff1fce2014-12-11 07:07:37 -0800764void SkCanvas::checkForDeferredSave() {
765 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800766 this->doSave();
767 }
768}
769
reedf0090cb2014-11-26 08:55:51 -0800770int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800771#ifdef SK_DEBUG
772 int count = 0;
773 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
774 for (;;) {
775 const MCRec* rec = (const MCRec*)iter.next();
776 if (!rec) {
777 break;
778 }
779 count += 1 + rec->fDeferredSaveCount;
780 }
781 SkASSERT(count == fSaveCount);
782#endif
783 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800784}
785
786int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800787 fSaveCount += 1;
788 fMCRec->fDeferredSaveCount += 1;
789 return this->getSaveCount() - 1; // return our prev value
790}
791
792void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800793 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700794
795 SkASSERT(fMCRec->fDeferredSaveCount > 0);
796 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800797 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800798}
799
800void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800801 if (fMCRec->fDeferredSaveCount > 0) {
802 SkASSERT(fSaveCount > 1);
803 fSaveCount -= 1;
804 fMCRec->fDeferredSaveCount -= 1;
805 } else {
806 // check for underflow
807 if (fMCStack.count() > 1) {
808 this->willRestore();
809 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700810 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800811 this->internalRestore();
812 this->didRestore();
813 }
reedf0090cb2014-11-26 08:55:51 -0800814 }
815}
816
817void SkCanvas::restoreToCount(int count) {
818 // sanity check
819 if (count < 1) {
820 count = 1;
821 }
mtkleinf0f14112014-12-12 08:46:25 -0800822
reedf0090cb2014-11-26 08:55:51 -0800823 int n = this->getSaveCount() - count;
824 for (int i = 0; i < n; ++i) {
825 this->restore();
826 }
827}
828
reed2ff1fce2014-12-11 07:07:37 -0800829void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000830 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700831 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000832 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000833
Mike Reedc42a1cd2017-02-14 14:25:14 -0500834 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000835}
836
reed4960eee2015-12-18 07:09:18 -0800837bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400838 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000839}
840
reed4960eee2015-12-18 07:09:18 -0800841bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700842 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500843 SkIRect clipBounds = this->getDeviceClipBounds();
844 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000845 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000846 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000847
reed96e657d2015-03-10 17:30:07 -0700848 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
849
Robert Phillips12078432018-05-17 11:17:39 -0400850 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
851 // If the image filter DAG affects transparent black then we will need to render
852 // out to the clip bounds
853 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000854 }
Robert Phillips12078432018-05-17 11:17:39 -0400855
856 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700857 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000858 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700859 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400860 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000861 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400862 inputSaveLayerBounds = clipBounds;
863 }
864
865 if (imageFilter) {
866 // expand the clip bounds by the image filter DAG to include extra content that might
867 // be required by the image filters.
868 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
869 SkImageFilter::kReverse_MapDirection,
870 &inputSaveLayerBounds);
871 }
872
873 SkIRect clippedSaveLayerBounds;
874 if (bounds) {
875 // For better or for worse, user bounds currently act as a hard clip on the layer's
876 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
877 clippedSaveLayerBounds = inputSaveLayerBounds;
878 } else {
879 // If there are no user bounds, we don't want to artificially restrict the resulting
880 // layer bounds, so allow the expanded clip bounds free reign.
881 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000882 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800883
884 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400885 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800886 if (BoundsAffectsClip(saveLayerFlags)) {
887 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
888 fMCRec->fRasterClip.setEmpty();
889 fDeviceClipBounds.setEmpty();
890 }
891 return false;
892 }
Robert Phillips12078432018-05-17 11:17:39 -0400893 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000894
reed4960eee2015-12-18 07:09:18 -0800895 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700896 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400897 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
898 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000899 }
900
901 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400902 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000903 }
Robert Phillips12078432018-05-17 11:17:39 -0400904
junov@chromium.orga907ac32012-02-24 21:54:07 +0000905 return true;
906}
907
reed4960eee2015-12-18 07:09:18 -0800908int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
909 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000910}
911
Cary Clarke041e312018-03-06 13:00:52 -0500912int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700913 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400914 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
915 // no need for the layer (or any of the draws until the matching restore()
916 this->save();
917 this->clipRect({0,0,0,0});
918 } else {
919 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
920 fSaveCount += 1;
921 this->internalSaveLayer(rec, strategy);
922 }
reed4960eee2015-12-18 07:09:18 -0800923 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800924}
925
Mike Reed148b7fd2018-12-18 17:38:18 -0500926int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
927 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
928 // Assuming clips never expand, if the request bounds is outside of the current clip
929 // there is no need to copy/restore the area, so just devolve back to a regular save.
930 this->save();
931 } else {
932 bool doTheWork = this->onDoSaveBehind(bounds);
933 fSaveCount += 1;
934 this->internalSave();
935 if (doTheWork) {
936 this->internalSaveBehind(bounds);
937 }
938 }
939 return this->getSaveCount() - 1;
940}
941
reeda2217ef2016-07-20 06:04:34 -0700942void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500943 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500944 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700945 SkDraw draw;
946 SkRasterClip rc;
947 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
948 if (!dst->accessPixels(&draw.fDst)) {
949 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800950 }
reeda2217ef2016-07-20 06:04:34 -0700951 draw.fMatrix = &SkMatrix::I();
952 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800953
954 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500955 if (filter) {
956 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
957 }
reeda2217ef2016-07-20 06:04:34 -0700958
Mike Reedc42a1cd2017-02-14 14:25:14 -0500959 int x = src->getOrigin().x() - dstOrigin.x();
960 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700961 auto special = src->snapSpecial();
962 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400963 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700964 }
robertphillips7354a4b2015-12-16 05:08:27 -0800965}
reed70ee31b2015-12-10 13:44:45 -0800966
Mike Kleine083f7c2018-02-07 12:54:27 -0500967static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500968 // Need to force L32 for now if we have an image filter.
969 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
970 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500971 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800972 }
Mike Klein649fb732018-02-26 15:09:16 -0500973
974 SkColorType ct = prev.colorType();
975 if (prev.bytesPerPixel() <= 4) {
976 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
977 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
978 ct = kN32_SkColorType;
979 }
980 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800981}
982
reed4960eee2015-12-18 07:09:18 -0800983void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700984 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800985 const SkRect* bounds = rec.fBounds;
986 const SkPaint* paint = rec.fPaint;
987 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
988
reed8c30a812016-04-20 16:36:51 -0700989 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400990 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700991 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400992 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700993 SkMatrix remainder;
994 SkSize scale;
995 /*
996 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
997 * but they do handle scaling. To accommodate this, we do the following:
998 *
999 * 1. Stash off the current CTM
1000 * 2. Decompose the CTM into SCALE and REMAINDER
1001 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1002 * contains the REMAINDER
1003 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1004 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1005 * of the original imagefilter, and draw that (via drawSprite)
1006 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1007 *
1008 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1009 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1010 */
reed96a04f32016-04-25 09:25:15 -07001011 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001012 stashedMatrix.decomposeScale(&scale, &remainder))
1013 {
1014 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001015 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001016 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1017 SkPaint* p = lazyP.set(*paint);
1018 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1019 SkFilterQuality::kLow_SkFilterQuality,
1020 sk_ref_sp(imageFilter)));
1021 imageFilter = p->getImageFilter();
1022 paint = p;
1023 }
reed8c30a812016-04-20 16:36:51 -07001024
junov@chromium.orga907ac32012-02-24 21:54:07 +00001025 // do this before we create the layer. We don't call the public save() since
1026 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001027 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001028
junov@chromium.orga907ac32012-02-24 21:54:07 +00001029 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001030 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001031 if (modifiedRec) {
1032 // In this case there will be no layer in which to stash the matrix so we need to
1033 // revert the prior MCRec to its earlier state.
1034 modifiedRec->fMatrix = stashedMatrix;
1035 }
reed2ff1fce2014-12-11 07:07:37 -08001036 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037 }
1038
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001039 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1040 // the clipRectBounds() call above?
1041 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001042 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001043 }
1044
reed8dc0ccb2015-03-20 06:32:52 -07001045 SkPixelGeometry geo = fProps.pixelGeometry();
1046 if (paint) {
reed76033be2015-03-14 10:54:31 -07001047 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001048 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001049 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001050 }
1051 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001052
robertphillips5139e502016-07-19 05:10:40 -07001053 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001054 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001055 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001056 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001057 }
reedb2db8982014-11-13 12:41:02 -08001058
Mike Kleine083f7c2018-02-07 12:54:27 -05001059 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001060
Hal Canary704cd322016-11-07 14:13:52 -05001061 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001062 {
Florin Malita07e4adf2019-01-07 16:34:18 -05001063 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType();
reeddaa57bf2015-05-15 10:39:17 -07001064 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001065 const bool trackCoverage =
1066 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001067 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001068 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001069 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001070 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001071 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1072 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001073 return;
reed61f501f2015-04-29 08:34:00 -07001074 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001075 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001076 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001077
Mike Reedb43a3e02017-02-11 10:18:58 -05001078 // only have a "next" if this new layer doesn't affect the clip (rare)
1079 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001080 fMCRec->fLayer = layer;
1081 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001082
Mike Reedc61abee2017-02-28 17:45:27 -05001083 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001084 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001085 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001086 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001087
Mike Reedc42a1cd2017-02-14 14:25:14 -05001088 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1089
1090 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1091 if (layer->fNext) {
1092 // need to punch a hole in the previous device, so we don't draw there, given that
1093 // the new top-layer will allow drawing to happen "below" it.
1094 SkRegion hole(ir);
1095 do {
1096 layer = layer->fNext;
1097 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1098 } while (layer->fNext);
1099 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001100}
1101
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001102int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001103 if (0xFF == alpha) {
1104 return this->saveLayer(bounds, nullptr);
1105 } else {
1106 SkPaint tmpPaint;
1107 tmpPaint.setAlpha(alpha);
1108 return this->saveLayer(bounds, &tmpPaint);
1109 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001110}
1111
Mike Reed148b7fd2018-12-18 17:38:18 -05001112void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1113 SkIRect devBounds;
1114 if (localBounds) {
1115 SkRect tmp;
1116 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1117 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1118 devBounds.setEmpty();
1119 }
1120 } else {
1121 devBounds = this->getDeviceClipBounds();
1122 }
1123 if (devBounds.isEmpty()) {
1124 return;
1125 }
1126
1127 SkBaseDevice* device = this->getTopDevice();
1128 if (nullptr == device) { // Do we still need this check???
1129 return;
1130 }
1131
1132 // need the bounds relative to the device itself
1133 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1134
1135 auto backImage = device->snapBackImage(devBounds);
1136 if (!backImage) {
1137 return;
1138 }
1139
1140 // we really need the save, so we can wack the fMCRec
1141 this->checkForDeferredSave();
1142
1143 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1144
1145 SkPaint paint;
1146 paint.setBlendMode(SkBlendMode::kClear);
1147 if (localBounds) {
1148 this->drawRect(*localBounds, paint);
1149 } else {
1150 this->drawPaint(paint);
1151 }
1152}
1153
reed@android.com8a1c16f2008-12-17 15:59:43 +00001154void SkCanvas::internalRestore() {
1155 SkASSERT(fMCStack.count() != 0);
1156
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001157 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001158 DeviceCM* layer = fMCRec->fLayer; // may be null
1159 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001160 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001161
Mike Reed148b7fd2018-12-18 17:38:18 -05001162 // move this out before we do the actual restore
1163 auto backImage = std::move(fMCRec->fBackImage);
1164
reed@android.com8a1c16f2008-12-17 15:59:43 +00001165 // now do the normal restore()
1166 fMCRec->~MCRec(); // balanced in save()
1167 fMCStack.pop_back();
1168 fMCRec = (MCRec*)fMCStack.back();
1169
Mike Reedc42a1cd2017-02-14 14:25:14 -05001170 if (fMCRec) {
1171 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1172 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001173
Mike Reed148b7fd2018-12-18 17:38:18 -05001174 if (backImage) {
1175 SkPaint paint;
1176 paint.setBlendMode(SkBlendMode::kDstOver);
1177 const int x = backImage->fLoc.x();
1178 const int y = backImage->fLoc.y();
1179 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1180 nullptr, SkMatrix::I());
1181 }
1182
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1184 since if we're being recorded, we don't want to record this (the
1185 recorder will have already recorded the restore).
1186 */
bsalomon49f085d2014-09-05 13:34:00 -07001187 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001188 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001189 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001190 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001191 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001192 layer->fPaint.get(),
1193 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001194 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001195 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001196 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001197 delete layer;
reedb679ca82015-04-07 04:40:48 -07001198 } else {
1199 // we're at the root
reeda499f902015-05-01 09:34:31 -07001200 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001201 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001202 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001203 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001204 }
msarettfbfa2582016-08-12 08:29:08 -07001205
1206 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001207 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001208 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1209 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210}
1211
reede8f30622016-03-23 18:59:25 -07001212sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001213 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001214 props = &fProps;
1215 }
1216 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001217}
1218
reede8f30622016-03-23 18:59:25 -07001219sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001220 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001221 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001222}
1223
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001224SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001225 return this->onImageInfo();
1226}
1227
1228SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001229 SkBaseDevice* dev = this->getDevice();
1230 if (dev) {
1231 return dev->imageInfo();
1232 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001233 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001234 }
1235}
1236
brianosman898235c2016-04-06 07:38:23 -07001237bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001238 return this->onGetProps(props);
1239}
1240
1241bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001242 SkBaseDevice* dev = this->getDevice();
1243 if (dev) {
1244 if (props) {
1245 *props = fProps;
1246 }
1247 return true;
1248 } else {
1249 return false;
1250 }
1251}
1252
reed6ceeebd2016-03-09 14:26:26 -08001253bool SkCanvas::peekPixels(SkPixmap* pmap) {
1254 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001255}
1256
reed884e97c2015-05-26 11:31:54 -07001257bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001258 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001259 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001260}
1261
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001262void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001263 SkPixmap pmap;
1264 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001265 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001266 }
1267 if (info) {
1268 *info = pmap.info();
1269 }
1270 if (rowBytes) {
1271 *rowBytes = pmap.rowBytes();
1272 }
1273 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001274 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001275 }
reed884e97c2015-05-26 11:31:54 -07001276 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001277}
1278
reed884e97c2015-05-26 11:31:54 -07001279bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001280 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001281 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001282}
1283
reed@android.com8a1c16f2008-12-17 15:59:43 +00001284/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285
Florin Malita53f77bd2017-04-28 13:48:37 -04001286void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1287 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001289 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290 paint = &tmp;
1291 }
reed@google.com4b226022011-01-11 18:32:13 +00001292
Ben Wagner2c312c42018-06-27 14:46:46 -04001293 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001294
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001296 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001297 paint = &looper.paint();
1298 SkImageFilter* filter = paint->getImageFilter();
1299 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001300 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001301 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1302 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001303 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1304 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001305 }
reed@google.com76dd2772012-01-05 21:15:07 +00001306 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001307 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001308 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309 }
reeda2217ef2016-07-20 06:04:34 -07001310
reed@google.com4e2b3d32011-04-07 14:18:59 +00001311 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001312}
1313
reed32704672015-12-16 08:27:10 -08001314/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001315
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001316void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001317 if (dx || dy) {
1318 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001319 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001320
reedfe69b502016-09-12 06:31:48 -07001321 // Translate shouldn't affect the is-scale-translateness of the matrix.
1322 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001323
Mike Reedc42a1cd2017-02-14 14:25:14 -05001324 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001325
reedfe69b502016-09-12 06:31:48 -07001326 this->didTranslate(dx,dy);
1327 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328}
1329
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001330void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001331 SkMatrix m;
1332 m.setScale(sx, sy);
1333 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334}
1335
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001336void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001337 SkMatrix m;
1338 m.setRotate(degrees);
1339 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340}
1341
bungeman7438bfc2016-07-12 15:01:19 -07001342void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1343 SkMatrix m;
1344 m.setRotate(degrees, px, py);
1345 this->concat(m);
1346}
1347
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001348void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001349 SkMatrix m;
1350 m.setSkew(sx, sy);
1351 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001352}
1353
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001354void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001355 if (matrix.isIdentity()) {
1356 return;
1357 }
1358
reed2ff1fce2014-12-11 07:07:37 -08001359 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001360 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001361 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001362
Mike Reed7627fa52017-02-08 10:07:53 -05001363 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001364
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001365 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001366}
1367
reed8c30a812016-04-20 16:36:51 -07001368void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001369 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001370 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001371
Mike Reedc42a1cd2017-02-14 14:25:14 -05001372 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001373}
1374
1375void SkCanvas::setMatrix(const SkMatrix& matrix) {
1376 this->checkForDeferredSave();
1377 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001378 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001379}
1380
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001382 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383}
1384
1385//////////////////////////////////////////////////////////////////////////////
1386
Mike Reedc1f77742016-12-09 09:00:50 -05001387void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001388 if (!rect.isFinite()) {
1389 return;
1390 }
reed2ff1fce2014-12-11 07:07:37 -08001391 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001392 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1393 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001394}
1395
Mike Reedc1f77742016-12-09 09:00:50 -05001396void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001397 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001398
Mike Reed7627fa52017-02-08 10:07:53 -05001399 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001400
reedc64eff52015-11-21 12:39:45 -08001401 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001402 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1403 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001404 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001405}
1406
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001407void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1408 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001409 if (fClipRestrictionRect.isEmpty()) {
1410 // we notify the device, but we *dont* resolve deferred saves (since we're just
1411 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001412 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001413 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001414 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001415 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001416 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001417 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001418 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1419 }
1420}
1421
Mike Reedc1f77742016-12-09 09:00:50 -05001422void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001423 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001424 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001425 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001426 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1427 } else {
1428 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001429 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001430}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001431
Mike Reedc1f77742016-12-09 09:00:50 -05001432void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001433 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001434
Brian Salomona3b45d42016-10-03 11:36:16 -04001435 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001436
Mike Reed7627fa52017-02-08 10:07:53 -05001437 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001438
Mike Reed20800c82017-11-15 16:09:04 -05001439 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1440 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001441 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001442}
1443
Mike Reedc1f77742016-12-09 09:00:50 -05001444void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001445 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001446 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001447
1448 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1449 SkRect r;
1450 if (path.isRect(&r)) {
1451 this->onClipRect(r, op, edgeStyle);
1452 return;
1453 }
1454 SkRRect rrect;
1455 if (path.isOval(&r)) {
1456 rrect.setOval(r);
1457 this->onClipRRect(rrect, op, edgeStyle);
1458 return;
1459 }
1460 if (path.isRRect(&rrect)) {
1461 this->onClipRRect(rrect, op, edgeStyle);
1462 return;
1463 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001464 }
robertphillips39f05382015-11-24 09:30:12 -08001465
1466 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001467}
1468
Mike Reedc1f77742016-12-09 09:00:50 -05001469void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001470 AutoValidateClip avc(this);
1471
Brian Salomona3b45d42016-10-03 11:36:16 -04001472 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001473
Mike Reed7627fa52017-02-08 10:07:53 -05001474 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001475
Brian Salomona3b45d42016-10-03 11:36:16 -04001476 const SkPath* rasterClipPath = &path;
1477 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001478 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1479 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001480 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001481}
1482
Mike Reedc1f77742016-12-09 09:00:50 -05001483void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001484 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001485 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001486}
1487
Mike Reedc1f77742016-12-09 09:00:50 -05001488void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001489 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001490
reed@google.com5c3d1472011-02-22 19:12:23 +00001491 AutoValidateClip avc(this);
1492
Mike Reed20800c82017-11-15 16:09:04 -05001493 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001494 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001495}
1496
reed@google.com819c9212011-02-23 18:56:55 +00001497#ifdef SK_DEBUG
1498void SkCanvas::validateClip() const {
1499 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001500 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001501 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001502 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001503 return;
1504 }
reed@google.com819c9212011-02-23 18:56:55 +00001505}
1506#endif
1507
Mike Reeda1361362017-03-07 09:37:29 -05001508bool SkCanvas::androidFramework_isClipAA() const {
1509 bool containsAA = false;
1510
1511 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1512
1513 return containsAA;
1514}
1515
1516class RgnAccumulator {
1517 SkRegion* fRgn;
1518public:
1519 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1520 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1521 SkIPoint origin = device->getOrigin();
1522 if (origin.x() | origin.y()) {
1523 rgn->translate(origin.x(), origin.y());
1524 }
1525 fRgn->op(*rgn, SkRegion::kUnion_Op);
1526 }
1527};
1528
1529void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1530 RgnAccumulator accum(rgn);
1531 SkRegion tmp;
1532
1533 rgn->setEmpty();
1534 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001535}
1536
reed@google.com5c3d1472011-02-22 19:12:23 +00001537///////////////////////////////////////////////////////////////////////////////
1538
reed@google.com754de5f2014-02-24 19:38:20 +00001539bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001540 return fMCRec->fRasterClip.isEmpty();
1541
1542 // TODO: should we only use the conservative answer in a recording canvas?
1543#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001544 SkBaseDevice* dev = this->getTopDevice();
1545 // if no device we return true
1546 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001547#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001548}
1549
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001550bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001551 SkBaseDevice* dev = this->getTopDevice();
1552 // if no device we return false
1553 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001554}
1555
msarettfbfa2582016-08-12 08:29:08 -07001556static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1557#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1558 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1559 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1560 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1561 return 0xF != _mm_movemask_ps(mask);
1562#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1563 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1564 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1565 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1566 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1567#else
1568 SkRect devRectAsRect;
1569 SkRect devClipAsRect;
1570 devRect.store(&devRectAsRect.fLeft);
1571 devClip.store(&devClipAsRect.fLeft);
1572 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1573#endif
1574}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001575
msarettfbfa2582016-08-12 08:29:08 -07001576// It's important for this function to not be inlined. Otherwise the compiler will share code
1577// between the fast path and the slow path, resulting in two slow paths.
1578static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1579 const SkMatrix& matrix) {
1580 SkRect deviceRect;
1581 matrix.mapRect(&deviceRect, src);
1582 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1583}
1584
1585bool SkCanvas::quickReject(const SkRect& src) const {
1586#ifdef SK_DEBUG
1587 // Verify that fDeviceClipBounds are set properly.
1588 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001589 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001590 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001591 } else {
msarettfbfa2582016-08-12 08:29:08 -07001592 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001593 }
msarettfbfa2582016-08-12 08:29:08 -07001594
msarett9637ea92016-08-18 14:03:30 -07001595 // Verify that fIsScaleTranslate is set properly.
1596 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001597#endif
1598
msarett9637ea92016-08-18 14:03:30 -07001599 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001600 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1601 }
1602
1603 // We inline the implementation of mapScaleTranslate() for the fast path.
1604 float sx = fMCRec->fMatrix.getScaleX();
1605 float sy = fMCRec->fMatrix.getScaleY();
1606 float tx = fMCRec->fMatrix.getTranslateX();
1607 float ty = fMCRec->fMatrix.getTranslateY();
1608 Sk4f scale(sx, sy, sx, sy);
1609 Sk4f trans(tx, ty, tx, ty);
1610
1611 // Apply matrix.
1612 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1613
1614 // Make sure left < right, top < bottom.
1615 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1616 Sk4f min = Sk4f::Min(ltrb, rblt);
1617 Sk4f max = Sk4f::Max(ltrb, rblt);
1618 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1619 // ARM this sequence generates the fastest (a single instruction).
1620 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1621
1622 // Check if the device rect is NaN or outside the clip.
1623 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001624}
1625
reed@google.com3b3e8952012-08-16 20:53:31 +00001626bool SkCanvas::quickReject(const SkPath& path) const {
1627 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001628}
1629
Mike Klein83c8dd92017-11-28 17:08:45 -05001630SkRect SkCanvas::getLocalClipBounds() const {
1631 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001632 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001633 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001634 }
1635
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001636 SkMatrix inverse;
1637 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001638 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001639 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001640 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001641
Mike Reed42e8c532017-01-23 14:09:13 -05001642 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001643 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001644 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001645
Mike Reedb57b9312018-04-23 12:12:54 -04001646 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001647 inverse.mapRect(&bounds, r);
1648 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001649}
1650
Mike Klein83c8dd92017-11-28 17:08:45 -05001651SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001652 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001653}
1654
reed@android.com8a1c16f2008-12-17 15:59:43 +00001655const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001656 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001657}
1658
Brian Osman11052242016-10-27 14:47:55 -04001659GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001660 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001661 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001662}
1663
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001664GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001665 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001666 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001667}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001668
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001669void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1670 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001671 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001672 if (outer.isEmpty()) {
1673 return;
1674 }
1675 if (inner.isEmpty()) {
1676 this->drawRRect(outer, paint);
1677 return;
1678 }
1679
1680 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001681 // be able to return ...
1682 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001683 //
1684 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001685 if (!outer.getBounds().contains(inner.getBounds())) {
1686 return;
1687 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001688
1689 this->onDrawDRRect(outer, inner, paint);
1690}
1691
reed41af9662015-01-05 07:49:08 -08001692void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001693 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001694 this->onDrawPaint(paint);
1695}
1696
1697void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001698 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001699 // To avoid redundant logic in our culling code and various backends, we always sort rects
1700 // before passing them along.
1701 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001702}
1703
msarettdca352e2016-08-26 06:37:45 -07001704void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001705 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001706 if (region.isEmpty()) {
1707 return;
1708 }
1709
1710 if (region.isRect()) {
1711 return this->drawIRect(region.getBounds(), paint);
1712 }
1713
1714 this->onDrawRegion(region, paint);
1715}
1716
reed41af9662015-01-05 07:49:08 -08001717void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001718 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001719 // To avoid redundant logic in our culling code and various backends, we always sort rects
1720 // before passing them along.
1721 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001722}
1723
1724void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001725 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001726 this->onDrawRRect(rrect, paint);
1727}
1728
1729void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001730 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001731 this->onDrawPoints(mode, count, pts, paint);
1732}
1733
Mike Reede88a1cb2017-03-17 09:50:46 -04001734void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1735 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001736 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001737 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001738 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1739 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001740 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001741}
1742
1743void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001744 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001745 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001746 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1747}
1748
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001749void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1750 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001751 TRACE_EVENT0("skia", TRACE_FUNC);
1752 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001753 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001754 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1755}
1756
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001757void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1758 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001759 TRACE_EVENT0("skia", TRACE_FUNC);
1760 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001761 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001762 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001763}
1764
1765void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001766 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001767 this->onDrawPath(path, paint);
1768}
1769
reeda85d4d02015-05-06 12:56:48 -07001770void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001771 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001772 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001773 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001774}
1775
Mike Reedc4e31092018-01-30 11:15:27 -05001776// Returns true if the rect can be "filled" : non-empty and finite
1777static bool fillable(const SkRect& r) {
1778 SkScalar w = r.width();
1779 SkScalar h = r.height();
1780 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1781}
1782
reede47829b2015-08-06 10:02:53 -07001783void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1784 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001785 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001786 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001787 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001788 return;
1789 }
1790 this->onDrawImageRect(image, &src, dst, paint, constraint);
1791}
reed41af9662015-01-05 07:49:08 -08001792
reed84984ef2015-07-17 07:09:43 -07001793void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1794 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001795 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001796 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001797}
1798
Brian Salomonf08002c2018-10-26 16:15:46 -04001799void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001800 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001801 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001802 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001803}
reede47829b2015-08-06 10:02:53 -07001804
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001805namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001806class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001807public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001808 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1809 if (!origPaint) {
1810 return;
1811 }
1812 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1813 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1814 }
1815 if (origPaint->getMaskFilter()) {
1816 fPaint.writable()->setMaskFilter(nullptr);
1817 }
1818 if (origPaint->isAntiAlias()) {
1819 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001820 }
1821 }
1822
1823 const SkPaint* get() const {
1824 return fPaint;
1825 }
1826
1827private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001828 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001829};
1830} // namespace
1831
reed4c21dc52015-06-25 12:32:03 -07001832void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1833 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001834 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001835 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001836 if (dst.isEmpty()) {
1837 return;
1838 }
msarett552bca92016-08-03 06:53:26 -07001839 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001840 LatticePaint latticePaint(paint);
1841 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001842 } else {
reede47829b2015-08-06 10:02:53 -07001843 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001844 }
reed4c21dc52015-06-25 12:32:03 -07001845}
1846
msarett16882062016-08-16 09:31:08 -07001847void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1848 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001849 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001850 RETURN_ON_NULL(image);
1851 if (dst.isEmpty()) {
1852 return;
1853 }
msarett71df2d72016-09-30 12:41:42 -07001854
1855 SkIRect bounds;
1856 Lattice latticePlusBounds = lattice;
1857 if (!latticePlusBounds.fBounds) {
1858 bounds = SkIRect::MakeWH(image->width(), image->height());
1859 latticePlusBounds.fBounds = &bounds;
1860 }
1861
1862 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001863 LatticePaint latticePaint(paint);
1864 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001865 } else {
1866 this->drawImageRect(image, dst, paint);
1867 }
1868}
1869
Brian Salomon1da5cad2018-11-21 09:21:18 -05001870void SkCanvas::experimental_DrawImageSetV1(const ImageSetEntry imageSet[], int cnt,
1871 SkFilterQuality filterQuality, SkBlendMode mode) {
1872 TRACE_EVENT0("skia", TRACE_FUNC);
1873 RETURN_ON_NULL(imageSet);
1874 RETURN_ON_FALSE(cnt);
1875
Brian Salomond003d222018-11-26 13:25:05 -05001876 this->onDrawImageSet(imageSet, cnt, filterQuality, mode);
Brian Salomon1da5cad2018-11-21 09:21:18 -05001877}
1878
reed41af9662015-01-05 07:49:08 -08001879void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001880 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001881 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001882 return;
1883 }
reed41af9662015-01-05 07:49:08 -08001884 this->onDrawBitmap(bitmap, dx, dy, paint);
1885}
1886
reede47829b2015-08-06 10:02:53 -07001887void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001888 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001889 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001890 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001891 return;
1892 }
reede47829b2015-08-06 10:02:53 -07001893 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001894}
1895
reed84984ef2015-07-17 07:09:43 -07001896void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1897 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001898 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001899}
1900
reede47829b2015-08-06 10:02:53 -07001901void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1902 SrcRectConstraint constraint) {
1903 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1904 constraint);
1905}
reede47829b2015-08-06 10:02:53 -07001906
reed41af9662015-01-05 07:49:08 -08001907void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1908 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001909 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001910 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001911 return;
1912 }
msarett552bca92016-08-03 06:53:26 -07001913 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001914 LatticePaint latticePaint(paint);
1915 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001916 } else {
reeda5517e22015-07-14 10:54:12 -07001917 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001918 }
reed41af9662015-01-05 07:49:08 -08001919}
1920
msarettc573a402016-08-02 08:05:56 -07001921void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1922 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001923 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001924 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001925 return;
1926 }
msarett71df2d72016-09-30 12:41:42 -07001927
1928 SkIRect bounds;
1929 Lattice latticePlusBounds = lattice;
1930 if (!latticePlusBounds.fBounds) {
1931 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1932 latticePlusBounds.fBounds = &bounds;
1933 }
1934
1935 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001936 LatticePaint latticePaint(paint);
1937 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001938 } else {
msarett16882062016-08-16 09:31:08 -07001939 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001940 }
msarettc573a402016-08-02 08:05:56 -07001941}
1942
reed71c3c762015-06-24 10:29:17 -07001943void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001944 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001945 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001946 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001947 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001948 if (count <= 0) {
1949 return;
1950 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001951 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001952 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001953 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001954}
1955
reedf70b5312016-03-04 16:36:20 -08001956void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001957 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001958 if (key) {
1959 this->onDrawAnnotation(rect, key, value);
1960 }
1961}
1962
reede47829b2015-08-06 10:02:53 -07001963void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1964 const SkPaint* paint, SrcRectConstraint constraint) {
1965 if (src) {
1966 this->drawImageRect(image, *src, dst, paint, constraint);
1967 } else {
1968 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1969 dst, paint, constraint);
1970 }
1971}
1972void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1973 const SkPaint* paint, SrcRectConstraint constraint) {
1974 if (src) {
1975 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1976 } else {
1977 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1978 dst, paint, constraint);
1979 }
1980}
1981
Mike Reed4204da22017-05-17 08:53:36 -04001982void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001983 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001984 this->onDrawShadowRec(path, rec);
1985}
1986
1987void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1988 SkPaint paint;
1989 const SkRect& pathBounds = path.getBounds();
1990
Ben Wagner2c312c42018-06-27 14:46:46 -04001991 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001992 while (iter.next()) {
1993 iter.fDevice->drawShadow(path, rec);
1994 }
1995 LOOPER_END
1996}
1997
reed@android.com8a1c16f2008-12-17 15:59:43 +00001998//////////////////////////////////////////////////////////////////////////////
1999// These are the virtual drawing methods
2000//////////////////////////////////////////////////////////////////////////////
2001
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002002void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002003 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002004 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2005 }
2006}
2007
reed41af9662015-01-05 07:49:08 -08002008void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002009 this->internalDrawPaint(paint);
2010}
2011
2012void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002013 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002014
2015 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002016 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002017 }
2018
reed@google.com4e2b3d32011-04-07 14:18:59 +00002019 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002020}
2021
reed41af9662015-01-05 07:49:08 -08002022void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2023 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002024 if ((long)count <= 0) {
2025 return;
2026 }
2027
Mike Reed822128b2017-02-28 16:41:03 -05002028 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002029 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002030 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002031 // special-case 2 points (common for drawing a single line)
2032 if (2 == count) {
2033 r.set(pts[0], pts[1]);
2034 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002035 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002036 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002037 if (!r.isFinite()) {
2038 return;
2039 }
Mike Reed822128b2017-02-28 16:41:03 -05002040 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002041 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2042 return;
2043 }
2044 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002045 }
reed@google.coma584aed2012-05-16 14:06:02 +00002046
halcanary96fcdcc2015-08-27 07:41:13 -07002047 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002048
Ben Wagner2c312c42018-06-27 14:46:46 -04002049 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002050
reed@android.com8a1c16f2008-12-17 15:59:43 +00002051 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002052 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002053 }
reed@google.com4b226022011-01-11 18:32:13 +00002054
reed@google.com4e2b3d32011-04-07 14:18:59 +00002055 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002056}
2057
reed4a167172016-08-18 17:15:25 -07002058static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2059 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07002060 (intptr_t)paint.getLooper() ) != 0;
2061}
2062
reed41af9662015-01-05 07:49:08 -08002063void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002064 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002065 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002066 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002067 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002068 return;
2069 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002070 }
reed@google.com4b226022011-01-11 18:32:13 +00002071
reed4a167172016-08-18 17:15:25 -07002072 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002073 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002074
reed4a167172016-08-18 17:15:25 -07002075 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002076 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002077 }
2078
2079 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002080 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002081 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002082 SkDrawIter iter(this);
2083 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002084 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002085 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002086 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002087}
2088
msarett44df6512016-08-25 13:54:30 -07002089void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002090 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002091 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002092 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002093 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2094 return;
2095 }
msarett44df6512016-08-25 13:54:30 -07002096 }
2097
Ben Wagner2c312c42018-06-27 14:46:46 -04002098 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002099
2100 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002101 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002102 }
2103
2104 LOOPER_END
2105}
2106
reed41af9662015-01-05 07:49:08 -08002107void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002108 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002109 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002110 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002111 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002112 return;
2113 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002114 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002115
Ben Wagner2c312c42018-06-27 14:46:46 -04002116 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002117
2118 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002119 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002120 }
2121
2122 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002123}
2124
bsalomonac3aa242016-08-19 11:25:19 -07002125void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2126 SkScalar sweepAngle, bool useCenter,
2127 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002128 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002129 if (paint.canComputeFastBounds()) {
2130 SkRect storage;
2131 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002132 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002133 return;
2134 }
bsalomonac3aa242016-08-19 11:25:19 -07002135 }
2136
Ben Wagner2c312c42018-06-27 14:46:46 -04002137 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002138
2139 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002140 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002141 }
2142
2143 LOOPER_END
2144}
2145
reed41af9662015-01-05 07:49:08 -08002146void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002147 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002148 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002149 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2150 return;
2151 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002152 }
2153
2154 if (rrect.isRect()) {
2155 // call the non-virtual version
2156 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002157 return;
2158 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002159 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002160 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2161 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002162 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002163
Ben Wagner2c312c42018-06-27 14:46:46 -04002164 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002165
2166 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002167 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002168 }
2169
2170 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002171}
2172
Mike Reed822128b2017-02-28 16:41:03 -05002173void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002174 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002175 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002176 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2177 return;
2178 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002179 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002180
Ben Wagner2c312c42018-06-27 14:46:46 -04002181 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002182
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002183 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002184 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002185 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002186
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002187 LOOPER_END
2188}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002189
reed41af9662015-01-05 07:49:08 -08002190void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002191 if (!path.isFinite()) {
2192 return;
2193 }
2194
Mike Reed822128b2017-02-28 16:41:03 -05002195 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002196 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002197 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002198 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2199 return;
2200 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002201 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002202
Mike Reed822128b2017-02-28 16:41:03 -05002203 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002204 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002205 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002206 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002207 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002208 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002209
Ben Wagner2c312c42018-06-27 14:46:46 -04002210 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002211
2212 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002213 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002214 }
2215
reed@google.com4e2b3d32011-04-07 14:18:59 +00002216 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002217}
2218
reed262a71b2015-12-05 13:07:27 -08002219bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002220 if (!paint.getImageFilter()) {
2221 return false;
2222 }
2223
2224 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002225 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002226 return false;
2227 }
2228
2229 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2230 // Once we can filter and the filter will return a result larger than itself, we should be
2231 // able to remove this constraint.
2232 // skbug.com/4526
2233 //
2234 SkPoint pt;
2235 ctm.mapXY(x, y, &pt);
2236 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2237 return ir.contains(fMCRec->fRasterClip.getBounds());
2238}
2239
Mike Reedf441cfc2018-04-11 14:50:16 -04002240// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2241// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2242// null.
2243static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2244 if (paintParam) {
2245 *real = *paintParam;
2246 real->setStyle(SkPaint::kFill_Style);
2247 real->setPathEffect(nullptr);
2248 paintParam = real;
2249 }
2250 return paintParam;
2251}
2252
reeda85d4d02015-05-06 12:56:48 -07002253void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002254 SkPaint realPaint;
2255 paint = init_image_paint(&realPaint, paint);
2256
reeda85d4d02015-05-06 12:56:48 -07002257 SkRect bounds = SkRect::MakeXYWH(x, y,
2258 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002259 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002260 SkRect tmp = bounds;
2261 if (paint) {
2262 paint->computeFastBounds(tmp, &tmp);
2263 }
2264 if (this->quickReject(tmp)) {
2265 return;
2266 }
reeda85d4d02015-05-06 12:56:48 -07002267 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002268 // At this point we need a real paint object. If the caller passed null, then we should
2269 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2270 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2271 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002272
reeda2217ef2016-07-20 06:04:34 -07002273 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002274 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2275 *paint);
2276 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002277 special = this->getDevice()->makeSpecial(image);
2278 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002279 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002280 }
2281 }
2282
reed262a71b2015-12-05 13:07:27 -08002283 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2284
reeda85d4d02015-05-06 12:56:48 -07002285 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002286 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002287 if (special) {
2288 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002289 iter.fDevice->ctm().mapXY(x, y, &pt);
2290 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002291 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002292 SkScalarRoundToInt(pt.fY), pnt,
2293 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002294 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002295 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002296 }
reeda85d4d02015-05-06 12:56:48 -07002297 }
halcanary9d524f22016-03-29 09:03:52 -07002298
reeda85d4d02015-05-06 12:56:48 -07002299 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002300}
2301
reed41af9662015-01-05 07:49:08 -08002302void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002303 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002304 SkPaint realPaint;
2305 paint = init_image_paint(&realPaint, paint);
2306
halcanary96fcdcc2015-08-27 07:41:13 -07002307 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002308 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002309 if (paint) {
2310 paint->computeFastBounds(dst, &storage);
2311 }
2312 if (this->quickReject(storage)) {
2313 return;
2314 }
reeda85d4d02015-05-06 12:56:48 -07002315 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002316 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002317
Ben Wagner2c312c42018-06-27 14:46:46 -04002318 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002319
reeda85d4d02015-05-06 12:56:48 -07002320 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002321 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002322 }
halcanary9d524f22016-03-29 09:03:52 -07002323
reeda85d4d02015-05-06 12:56:48 -07002324 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002325}
2326
reed41af9662015-01-05 07:49:08 -08002327void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002328 SkDEBUGCODE(bitmap.validate();)
2329
reed33366972015-10-08 09:22:02 -07002330 if (bitmap.drawsNothing()) {
2331 return;
2332 }
2333
Mike Reedf441cfc2018-04-11 14:50:16 -04002334 SkPaint realPaint;
2335 init_image_paint(&realPaint, paint);
2336 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002337
Mike Reed822128b2017-02-28 16:41:03 -05002338 SkRect bounds;
2339 bitmap.getBounds(&bounds);
2340 bounds.offset(x, y);
2341 bool canFastBounds = paint->canComputeFastBounds();
2342 if (canFastBounds) {
2343 SkRect storage;
2344 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002345 return;
2346 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002347 }
reed@google.com4b226022011-01-11 18:32:13 +00002348
reeda2217ef2016-07-20 06:04:34 -07002349 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002350 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2351 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002352 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002353 special = this->getDevice()->makeSpecial(bitmap);
2354 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002355 drawAsSprite = false;
2356 }
2357 }
2358
Mike Reed822128b2017-02-28 16:41:03 -05002359 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002360
2361 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002362 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002363 if (special) {
reed262a71b2015-12-05 13:07:27 -08002364 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002365 iter.fDevice->ctm().mapXY(x, y, &pt);
2366 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002367 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002368 SkScalarRoundToInt(pt.fY), pnt,
2369 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002370 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002371 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002372 }
reed33366972015-10-08 09:22:02 -07002373 }
msarettfbfa2582016-08-12 08:29:08 -07002374
reed33366972015-10-08 09:22:02 -07002375 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002376}
2377
reed@google.com9987ec32011-09-07 11:57:52 +00002378// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002379void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002380 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002381 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002382 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002383 return;
2384 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002385
halcanary96fcdcc2015-08-27 07:41:13 -07002386 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002387 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002388 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2389 return;
2390 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002391 }
reed@google.com3d608122011-11-21 15:16:16 +00002392
reed@google.com33535f32012-09-25 15:37:50 +00002393 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002394 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002395 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002396 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002397
Ben Wagner2c312c42018-06-27 14:46:46 -04002398 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002399
reed@google.com33535f32012-09-25 15:37:50 +00002400 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002401 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002402 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002403
reed@google.com33535f32012-09-25 15:37:50 +00002404 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002405}
2406
reed41af9662015-01-05 07:49:08 -08002407void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002408 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002409 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002410 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002411}
2412
reed4c21dc52015-06-25 12:32:03 -07002413void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2414 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002415 SkPaint realPaint;
2416 paint = init_image_paint(&realPaint, paint);
2417
halcanary96fcdcc2015-08-27 07:41:13 -07002418 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002419 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002420 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2421 return;
2422 }
reed@google.com3d608122011-11-21 15:16:16 +00002423 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002424 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002425
Ben Wagner2c312c42018-06-27 14:46:46 -04002426 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002427
reed4c21dc52015-06-25 12:32:03 -07002428 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002429 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002430 }
halcanary9d524f22016-03-29 09:03:52 -07002431
reed4c21dc52015-06-25 12:32:03 -07002432 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002433}
2434
reed41af9662015-01-05 07:49:08 -08002435void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2436 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002437 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002438 SkPaint realPaint;
2439 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002440
halcanary96fcdcc2015-08-27 07:41:13 -07002441 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002442 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002443 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2444 return;
2445 }
reed4c21dc52015-06-25 12:32:03 -07002446 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002447 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002448
Ben Wagner2c312c42018-06-27 14:46:46 -04002449 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002450
reed4c21dc52015-06-25 12:32:03 -07002451 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002452 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002453 }
halcanary9d524f22016-03-29 09:03:52 -07002454
reed4c21dc52015-06-25 12:32:03 -07002455 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002456}
2457
msarett16882062016-08-16 09:31:08 -07002458void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2459 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002460 SkPaint realPaint;
2461 paint = init_image_paint(&realPaint, paint);
2462
msarett16882062016-08-16 09:31:08 -07002463 if (nullptr == paint || paint->canComputeFastBounds()) {
2464 SkRect storage;
2465 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2466 return;
2467 }
2468 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002469 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002470
Ben Wagner2c312c42018-06-27 14:46:46 -04002471 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002472
2473 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002474 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002475 }
2476
2477 LOOPER_END
2478}
2479
Brian Salomond003d222018-11-26 13:25:05 -05002480void SkCanvas::onDrawImageSet(const ImageSetEntry imageSet[], int count,
Brian Salomond7065e72018-10-12 11:42:02 -04002481 SkFilterQuality filterQuality, SkBlendMode mode) {
2482 SkPaint paint;
Brian Salomon23356442018-11-30 15:33:19 -05002483 LOOPER_BEGIN(paint, nullptr)
Brian Salomond7065e72018-10-12 11:42:02 -04002484 while (iter.next()) {
Brian Salomond003d222018-11-26 13:25:05 -05002485 iter.fDevice->drawImageSet(imageSet, count, filterQuality, mode);
Brian Salomond7065e72018-10-12 11:42:02 -04002486 }
2487 LOOPER_END
2488}
2489
msarett16882062016-08-16 09:31:08 -07002490void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2491 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002492 SkPaint realPaint;
2493 paint = init_image_paint(&realPaint, paint);
2494
msarett16882062016-08-16 09:31:08 -07002495 if (nullptr == paint || paint->canComputeFastBounds()) {
2496 SkRect storage;
2497 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2498 return;
2499 }
2500 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002501 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002502
Ben Wagner2c312c42018-06-27 14:46:46 -04002503 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002504
2505 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002506 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002507 }
2508
2509 LOOPER_END
2510}
2511
fmalita00d5c2c2014-08-21 08:53:26 -07002512void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2513 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002514 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002515 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002516 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002517 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002518 SkRect tmp;
2519 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2520 return;
2521 }
2522 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002523 }
2524
fmalita024f9962015-03-03 19:08:17 -08002525 // We cannot filter in the looper as we normally do, because the paint is
2526 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002527 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002528
fmalitaaa1b9122014-08-28 14:32:24 -07002529 while (iter.next()) {
Mike Reed30cf62b2018-12-20 11:18:24 -05002530 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002531 }
2532
fmalitaaa1b9122014-08-28 14:32:24 -07002533 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002534}
2535
Mike Reed358fcad2018-11-23 15:27:51 -05002536// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002537void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002538 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2539 TRACE_EVENT0("skia", TRACE_FUNC);
2540 if (byteLength) {
2541 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002542 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002543 }
2544}
Mike Reed4f81bb72019-01-23 09:23:00 -05002545
fmalita00d5c2c2014-08-21 08:53:26 -07002546void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2547 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002548 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002549 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002550 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002551 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002552}
reed@google.come0d9ce82014-04-23 04:00:17 +00002553
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002554void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002555 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002556 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002557
2558 while (iter.next()) {
2559 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002560 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002561 }
2562
2563 LOOPER_END
2564}
2565
dandovb3c9d1c2014-08-12 08:34:29 -07002566void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002567 const SkPoint texCoords[4], SkBlendMode bmode,
2568 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002569 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002570 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002571 return;
2572 }
mtklein6cfa73a2014-08-13 13:33:49 -07002573
Mike Reedfaba3712016-11-03 14:45:31 -04002574 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002575}
2576
2577void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002578 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002579 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002580 // Since a patch is always within the convex hull of the control points, we discard it when its
2581 // bounding rectangle is completely outside the current clip.
2582 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002583 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002584 if (this->quickReject(bounds)) {
2585 return;
2586 }
mtklein6cfa73a2014-08-13 13:33:49 -07002587
Ben Wagner2c312c42018-06-27 14:46:46 -04002588 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002589
dandovecfff212014-08-04 10:02:00 -07002590 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002591 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002592 }
mtklein6cfa73a2014-08-13 13:33:49 -07002593
dandovecfff212014-08-04 10:02:00 -07002594 LOOPER_END
2595}
2596
reeda8db7282015-07-07 10:22:31 -07002597void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002598#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002599 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002600#endif
reede3b38ce2016-01-08 09:18:44 -08002601 RETURN_ON_NULL(dr);
2602 if (x || y) {
2603 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2604 this->onDrawDrawable(dr, &matrix);
2605 } else {
2606 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002607 }
2608}
2609
reeda8db7282015-07-07 10:22:31 -07002610void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002611#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002612 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002613#endif
reede3b38ce2016-01-08 09:18:44 -08002614 RETURN_ON_NULL(dr);
2615 if (matrix && matrix->isIdentity()) {
2616 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002617 }
reede3b38ce2016-01-08 09:18:44 -08002618 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002619}
2620
2621void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002622 // drawable bounds are no longer reliable (e.g. android displaylist)
2623 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002624 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002625}
2626
reed71c3c762015-06-24 10:29:17 -07002627void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002628 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002629 const SkRect* cull, const SkPaint* paint) {
2630 if (cull && this->quickReject(*cull)) {
2631 return;
2632 }
2633
2634 SkPaint pnt;
2635 if (paint) {
2636 pnt = *paint;
2637 }
halcanary9d524f22016-03-29 09:03:52 -07002638
Ben Wagner2c312c42018-06-27 14:46:46 -04002639 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002640 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002641 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002642 }
2643 LOOPER_END
2644}
2645
reedf70b5312016-03-04 16:36:20 -08002646void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2647 SkASSERT(key);
2648
2649 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002650 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002651 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002652 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002653 }
2654 LOOPER_END
2655}
2656
reed@android.com8a1c16f2008-12-17 15:59:43 +00002657//////////////////////////////////////////////////////////////////////////////
2658// These methods are NOT virtual, and therefore must call back into virtual
2659// methods, rather than actually drawing themselves.
2660//////////////////////////////////////////////////////////////////////////////
2661
reed374772b2016-10-05 17:33:02 -07002662void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002663 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002664 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002665 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002666 this->drawPaint(paint);
2667}
2668
2669void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002670 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002671 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2672}
2673
Mike Reed3661bc92017-02-22 13:21:42 -05002674void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002675 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002676 pts[0].set(x0, y0);
2677 pts[1].set(x1, y1);
2678 this->drawPoints(kLines_PointMode, 2, pts, paint);
2679}
2680
Mike Reed3661bc92017-02-22 13:21:42 -05002681void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002682 if (radius < 0) {
2683 radius = 0;
2684 }
2685
2686 SkRect r;
2687 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002688 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002689}
2690
2691void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2692 const SkPaint& paint) {
2693 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002694 SkRRect rrect;
2695 rrect.setRectXY(r, rx, ry);
2696 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697 } else {
2698 this->drawRect(r, paint);
2699 }
2700}
2701
reed@android.com8a1c16f2008-12-17 15:59:43 +00002702void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2703 SkScalar sweepAngle, bool useCenter,
2704 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002705 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002706 if (oval.isEmpty() || !sweepAngle) {
2707 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002708 }
bsalomon21af9ca2016-08-25 12:29:23 -07002709 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002710}
2711
reed@android.comf76bacf2009-05-13 14:00:33 +00002712///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002713#ifdef SK_DISABLE_SKPICTURE
2714void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002715
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002716
2717void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2718 const SkPaint* paint) {}
2719#else
Mike Klein88d90712018-01-27 17:30:04 +00002720/**
2721 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2722 * against the playback cost of recursing into the subpicture to get at its actual ops.
2723 *
2724 * For now we pick a conservatively small value, though measurement (and other heuristics like
2725 * the type of ops contained) may justify changing this value.
2726 */
2727#define kMaxPictureOpsToUnrollInsteadOfRef 1
2728
reedd5fa1a42014-08-09 11:08:05 -07002729void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002730 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002731 RETURN_ON_NULL(picture);
2732
reede3b38ce2016-01-08 09:18:44 -08002733 if (matrix && matrix->isIdentity()) {
2734 matrix = nullptr;
2735 }
Mike Klein88d90712018-01-27 17:30:04 +00002736 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2737 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2738 picture->playback(this);
2739 } else {
2740 this->onDrawPicture(picture, matrix, paint);
2741 }
reedd5fa1a42014-08-09 11:08:05 -07002742}
robertphillips9b14f262014-06-04 05:40:44 -07002743
reedd5fa1a42014-08-09 11:08:05 -07002744void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2745 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002746 if (!paint || paint->canComputeFastBounds()) {
2747 SkRect bounds = picture->cullRect();
2748 if (paint) {
2749 paint->computeFastBounds(bounds, &bounds);
2750 }
2751 if (matrix) {
2752 matrix->mapRect(&bounds);
2753 }
2754 if (this->quickReject(bounds)) {
2755 return;
2756 }
2757 }
2758
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002759 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002760 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002761}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002762#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002763
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764///////////////////////////////////////////////////////////////////////////////
2765///////////////////////////////////////////////////////////////////////////////
2766
reed3aafe112016-08-18 12:45:34 -07002767SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002768 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769
2770 SkASSERT(canvas);
2771
reed3aafe112016-08-18 12:45:34 -07002772 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002773 fDone = !fImpl->next();
2774}
2775
2776SkCanvas::LayerIter::~LayerIter() {
2777 fImpl->~SkDrawIter();
2778}
2779
2780void SkCanvas::LayerIter::next() {
2781 fDone = !fImpl->next();
2782}
2783
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002784SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002785 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786}
2787
2788const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002789 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790}
2791
2792const SkPaint& SkCanvas::LayerIter::paint() const {
2793 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002794 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795 paint = &fDefaultPaint;
2796 }
2797 return *paint;
2798}
2799
Mike Reedca37f322018-03-08 13:22:16 -05002800SkIRect SkCanvas::LayerIter::clipBounds() const {
2801 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002802}
2803
reed@android.com8a1c16f2008-12-17 15:59:43 +00002804int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2805int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002806
2807///////////////////////////////////////////////////////////////////////////////
2808
Mike Reed5df49342016-11-12 08:06:55 -06002809std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002810 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002811 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002812 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002813 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002814
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002815 SkBitmap bitmap;
2816 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002817 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002818 }
Mike Reed12f77342017-11-08 11:19:52 -05002819
2820 return props ?
2821 skstd::make_unique<SkCanvas>(bitmap, *props) :
2822 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002823}
reedd5fa1a42014-08-09 11:08:05 -07002824
2825///////////////////////////////////////////////////////////////////////////////
2826
Florin Malitaee424ac2016-12-01 12:47:59 -05002827SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002828 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002829
Florin Malita439ace92016-12-02 12:05:41 -05002830SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002831 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002832
Herb Derbyefe39bc2018-05-01 17:06:20 -04002833SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002834 : INHERITED(device) {}
2835
Florin Malitaee424ac2016-12-01 12:47:59 -05002836SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2837 (void)this->INHERITED::getSaveLayerStrategy(rec);
2838 return kNoLayer_SaveLayerStrategy;
2839}
2840
Mike Reed148b7fd2018-12-18 17:38:18 -05002841bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2842 return false;
2843}
2844
Florin Malitaee424ac2016-12-01 12:47:59 -05002845///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002846
reed73603f32016-09-20 08:42:38 -07002847static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2848static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2849static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2850static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2851static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2852static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002853
2854///////////////////////////////////////////////////////////////////////////////////////////////////
2855
2856SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2857 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002858 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002859 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2860 SkIPoint origin = dev->getOrigin();
2861 SkMatrix ctm = this->getTotalMatrix();
2862 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2863
2864 SkIRect clip = fMCRec->fRasterClip.getBounds();
2865 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002866 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002867 clip.setEmpty();
2868 }
2869
2870 fAllocator->updateHandle(handle, ctm, clip);
2871 return handle;
2872 }
2873 return nullptr;
2874}
2875
2876static bool install(SkBitmap* bm, const SkImageInfo& info,
2877 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002878 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002879}
2880
2881SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2882 SkBitmap* bm) {
2883 SkRasterHandleAllocator::Rec rec;
2884 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2885 return nullptr;
2886 }
2887 return rec.fHandle;
2888}
2889
2890std::unique_ptr<SkCanvas>
2891SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2892 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04002893 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05002894 return nullptr;
2895 }
2896
2897 SkBitmap bm;
2898 Handle hndl;
2899
2900 if (rec) {
2901 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2902 } else {
2903 hndl = alloc->allocBitmap(info, &bm);
2904 }
2905 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2906}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002907
2908///////////////////////////////////////////////////////////////////////////////////////////////////
2909
2910