blob: fdc7d59fd857e35d80182efe5df9140148282c40 [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"
Florin Malitaee424ac2016-12-01 12:47:59 -050027#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070028#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070029#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070030#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040031#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000032#include "SkPicture.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040033#include "SkRRect.h"
reed@google.com00177082011-10-12 14:34:30 +000034#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050035#include "SkRasterHandleAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080036#include "SkSpecialImage.h"
Herb Derby41f4f312018-06-06 17:45:53 +000037#include "SkStrikeCache.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040038#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000039#include "SkSurface_Base.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040040#include "SkTLazy.h"
fmalita7ba7aa72014-08-29 09:46:36 -070041#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000042#include "SkTextFormatParams.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040043#include "SkTo.h"
danakj8f757f52014-11-04 11:48:43 -080044#include "SkTraceEvent.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040045#include "SkVertices.h"
46
bungemand3ebb482015-08-05 13:57:49 -070047#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000048
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000049#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080050#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050051#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052#endif
53
reede3b38ce2016-01-08 09:18:44 -080054#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050055#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080056
Mike Reed139e5e02017-03-08 11:29:33 -050057///////////////////////////////////////////////////////////////////////////////////////////////////
58
reedc83a2972015-07-16 07:40:45 -070059/*
60 * Return true if the drawing this rect would hit every pixels in the canvas.
61 *
62 * Returns false if
63 * - rect does not contain the canvas' bounds
64 * - paint is not fill
65 * - paint would blur or otherwise change the coverage of the rect
66 */
67bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
68 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070069 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
70 (int)kNone_ShaderOverrideOpacity,
71 "need_matching_enums0");
72 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
73 (int)kOpaque_ShaderOverrideOpacity,
74 "need_matching_enums1");
75 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
76 (int)kNotOpaque_ShaderOverrideOpacity,
77 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070078
79 const SkISize size = this->getBaseLayerSize();
80 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050081
82 // if we're clipped at all, we can't overwrite the entire surface
83 {
84 SkBaseDevice* base = this->getDevice();
85 SkBaseDevice* top = this->getTopDevice();
86 if (base != top) {
87 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
88 }
89 if (!base->clipIsWideOpen()) {
90 return false;
91 }
reedc83a2972015-07-16 07:40:45 -070092 }
93
94 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070095 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070096 return false; // conservative
97 }
halcanaryc5769b22016-08-10 07:13:21 -070098
99 SkRect devRect;
100 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
101 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700102 return false;
103 }
104 }
105
106 if (paint) {
107 SkPaint::Style paintStyle = paint->getStyle();
108 if (!(paintStyle == SkPaint::kFill_Style ||
109 paintStyle == SkPaint::kStrokeAndFill_Style)) {
110 return false;
111 }
112 if (paint->getMaskFilter() || paint->getLooper()
113 || paint->getPathEffect() || paint->getImageFilter()) {
114 return false; // conservative
115 }
116 }
117 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
118}
119
120///////////////////////////////////////////////////////////////////////////////////////////////////
121
reed@google.comda17f752012-08-16 18:27:05 +0000122// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123//#define SK_TRACE_SAVERESTORE
124
125#ifdef SK_TRACE_SAVERESTORE
126 static int gLayerCounter;
127 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
128 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
129
130 static int gRecCounter;
131 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
132 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
133
134 static int gCanvasCounter;
135 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
136 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
137#else
138 #define inc_layer()
139 #define dec_layer()
140 #define inc_rec()
141 #define dec_rec()
142 #define inc_canvas()
143 #define dec_canvas()
144#endif
145
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000146typedef SkTLazy<SkPaint> SkLazyPaint;
147
reedc83a2972015-07-16 07:40:45 -0700148void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000149 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700150 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
151 ? SkSurface::kDiscard_ContentChangeMode
152 : SkSurface::kRetain_ContentChangeMode);
153 }
154}
155
156void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
157 ShaderOverrideOpacity overrideOpacity) {
158 if (fSurfaceBase) {
159 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
160 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
161 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
162 // and therefore we don't care which mode we're in.
163 //
164 if (fSurfaceBase->outstandingImageSnapshot()) {
165 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
166 mode = SkSurface::kDiscard_ContentChangeMode;
167 }
168 }
169 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000170 }
171}
172
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000175/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 The clip/matrix/proc are fields that reflect the top of the save/restore
177 stack. Whenever the canvas changes, it marks a dirty flag, and then before
178 these are used (assuming we're not on a layer) we rebuild these cache
179 values: they reflect the top of the save stack, but translated and clipped
180 by the device's XY offset and bitmap-bounds.
181*/
182struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400183 DeviceCM* fNext;
184 sk_sp<SkBaseDevice> fDevice;
185 SkRasterClip fClip;
186 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
187 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400188 sk_sp<SkImage> fClipImage;
189 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190
Florin Malita53f77bd2017-04-28 13:48:37 -0400191 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000192 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700193 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400194 , fDevice(std::move(device))
195 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700196 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000197 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400198 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400199 {}
reed@google.com4b226022011-01-11 18:32:13 +0000200
mtkleinfeaadee2015-04-08 11:25:48 -0700201 void reset(const SkIRect& bounds) {
202 SkASSERT(!fPaint);
203 SkASSERT(!fNext);
204 SkASSERT(fDevice);
205 fClip.setRect(bounds);
206 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207};
208
Mike Reed148b7fd2018-12-18 17:38:18 -0500209namespace {
210// Encapsulate state needed to restore from saveBehind()
211struct BackImage {
212 sk_sp<SkSpecialImage> fImage;
213 SkIPoint fLoc;
214};
215}
216
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217/* This is the record we keep for each save/restore level in the stack.
218 Since a level optionally copies the matrix and/or stack, we have pointers
219 for these fields. If the value is copied for this level, the copy is
220 stored in the ...Storage field, and the pointer points to that. If the
221 value is not copied for this level, we ignore ...Storage, and just point
222 at the corresponding value in the previous level in the stack.
223*/
224class SkCanvas::MCRec {
225public:
Mike Reed148b7fd2018-12-18 17:38:18 -0500226 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 /* If there are any layers in the stack, this points to the top-most
228 one that is at or below this level in the stack (so we know what
229 bitmap/device to draw into from this level. This value is NOT
230 reference counted, since the real owner is either our fLayer field,
231 or a previous one in a lower level.)
232 */
Mike Reed148b7fd2018-12-18 17:38:18 -0500233 DeviceCM* fTopLayer;
234 std::unique_ptr<BackImage> fBackImage;
235 SkConservativeClip fRasterClip;
236 SkMatrix fMatrix;
237 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238
Mike Reeda1361362017-03-07 09:37:29 -0500239 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700240 fLayer = nullptr;
241 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800242 fMatrix.reset();
243 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700244
reedd9544982014-09-09 18:46:22 -0700245 // don't bother initializing fNext
246 inc_rec();
247 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400248 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700249 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700250 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800251 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700252
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 // don't bother initializing fNext
254 inc_rec();
255 }
256 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700257 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258 dec_rec();
259 }
mtkleinfeaadee2015-04-08 11:25:48 -0700260
261 void reset(const SkIRect& bounds) {
262 SkASSERT(fLayer);
263 SkASSERT(fDeferredSaveCount == 0);
264
265 fMatrix.reset();
266 fRasterClip.setRect(bounds);
267 fLayer->reset(bounds);
268 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000269};
270
Mike Reeda1361362017-03-07 09:37:29 -0500271class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272public:
Mike Reeda1361362017-03-07 09:37:29 -0500273 SkDrawIter(SkCanvas* canvas)
274 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
275 {}
reed@google.com4b226022011-01-11 18:32:13 +0000276
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000278 const DeviceCM* rec = fCurrLayer;
279 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400280 fDevice = rec->fDevice.get();
281 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700283 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284 return true;
285 }
286 return false;
287 }
reed@google.com4b226022011-01-11 18:32:13 +0000288
reed@google.com6f8f2922011-03-04 22:27:10 +0000289 int getX() const { return fDevice->getOrigin().x(); }
290 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000292
Mike Reed99330ba2017-02-22 11:01:08 -0500293 SkBaseDevice* fDevice;
294
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 const DeviceCM* fCurrLayer;
297 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298};
299
Florin Malita713b8ef2017-04-28 10:57:24 -0400300#define FOR_EACH_TOP_DEVICE( code ) \
301 do { \
302 DeviceCM* layer = fMCRec->fTopLayer; \
303 while (layer) { \
304 SkBaseDevice* device = layer->fDevice.get(); \
305 if (device) { \
306 code; \
307 } \
308 layer = layer->fNext; \
309 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500310 } while (0)
311
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312/////////////////////////////////////////////////////////////////////////////
313
reeddbc3cef2015-04-29 12:18:57 -0700314static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
315 return lazy->isValid() ? lazy->get() : lazy->set(orig);
316}
317
318/**
319 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700320 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700321 */
reedd053ce92016-03-22 10:17:23 -0700322static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700323 SkImageFilter* imgf = paint.getImageFilter();
324 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700325 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700326 }
327
reedd053ce92016-03-22 10:17:23 -0700328 SkColorFilter* imgCFPtr;
329 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700330 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700331 }
reedd053ce92016-03-22 10:17:23 -0700332 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700333
334 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700335 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700336 // there is no existing paint colorfilter, so we can just return the imagefilter's
337 return imgCF;
338 }
339
340 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
341 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500342 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700343}
344
senorblanco87e066e2015-10-28 11:23:36 -0700345/**
346 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
347 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
348 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
349 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
350 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
351 * conservative "effective" bounds based on the settings in the paint... with one exception. This
352 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
353 * deliberately ignored.
354 */
355static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
356 const SkRect& rawBounds,
357 SkRect* storage) {
358 SkPaint tmpUnfiltered(paint);
359 tmpUnfiltered.setImageFilter(nullptr);
360 if (tmpUnfiltered.canComputeFastBounds()) {
361 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
362 } else {
363 return rawBounds;
364 }
365}
366
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367class AutoDrawLooper {
368public:
senorblanco87e066e2015-10-28 11:23:36 -0700369 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
370 // paint. It's used to determine the size of the offscreen layer for filters.
371 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700372 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700373 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000374 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700375 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000376 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700377 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000378 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379
reedd053ce92016-03-22 10:17:23 -0700380 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700381 if (simplifiedCF) {
382 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700383 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700384 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700385 fPaint = paint;
386 }
387
388 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700389 /**
390 * We implement ImageFilters for a given draw by creating a layer, then applying the
391 * imagefilter to the pixels of that layer (its backing surface/image), and then
392 * we call restore() to xfer that layer to the main canvas.
393 *
394 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
395 * 2. Generate the src pixels:
396 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
397 * return (fPaint). We then draw the primitive (using srcover) into a cleared
398 * buffer/surface.
399 * 3. Restore the layer created in #1
400 * The imagefilter is passed the buffer/surface from the layer (now filled with the
401 * src pixels of the primitive). It returns a new "filtered" buffer, which we
402 * draw onto the previous layer using the xfermode from the original paint.
403 */
reed@google.com8926b162012-03-23 15:36:36 +0000404 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500405 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700406 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700407 SkRect storage;
408 if (rawBounds) {
409 // Make rawBounds include all paint outsets except for those due to image filters.
410 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
411 }
reedbfd5f172016-01-07 11:28:08 -0800412 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700413 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700414 fTempLayerForImageFilter = true;
415 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000416 }
417
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000418 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500419 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000420 fIsSimple = false;
421 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700422 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000423 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400424 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000425 }
426 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000427
reed@android.com8a1c16f2008-12-17 15:59:43 +0000428 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700429 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000430 fCanvas->internalRestore();
431 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000432 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000434
reed@google.com4e2b3d32011-04-07 14:18:59 +0000435 const SkPaint& paint() const {
436 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400437 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000438 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000439 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000440
Ben Wagner2c312c42018-06-27 14:46:46 -0400441 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000442 if (fDone) {
443 return false;
444 } else if (fIsSimple) {
445 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000446 return !fPaint->nothingToDraw();
447 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400448 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000449 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000450 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000451
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500453 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700454 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000455 SkCanvas* fCanvas;
456 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000457 const SkPaint* fPaint;
458 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700459 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000460 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000461 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000462 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400463 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000464
Ben Wagner2c312c42018-06-27 14:46:46 -0400465 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466};
467
Ben Wagner2c312c42018-06-27 14:46:46 -0400468bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700469 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000470 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400471 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000472
reeddbc3cef2015-04-29 12:18:57 -0700473 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
474 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400475 // never want our downstream clients (i.e. devices) to see loopers
476 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000477
reed5c476fb2015-04-20 08:04:21 -0700478 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700479 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700480 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000481 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000482
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000483 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000484 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000485 return false;
486 }
reed@google.com129ec222012-05-15 13:24:09 +0000487 fPaint = paint;
488
489 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400490 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000491 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000492 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000493 return true;
494}
495
reed@android.com8a1c16f2008-12-17 15:59:43 +0000496////////// macros to place around the internal draw calls //////////////////
497
reed3aafe112016-08-18 12:45:34 -0700498#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
499 this->predrawNotify(); \
500 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400501 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800502 SkDrawIter iter(this);
503
504
Ben Wagner2c312c42018-06-27 14:46:46 -0400505#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000506 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700507 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400508 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000509 SkDrawIter iter(this);
510
Ben Wagner2c312c42018-06-27 14:46:46 -0400511#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000512 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700513 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400514 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000515 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000516
Ben Wagner2c312c42018-06-27 14:46:46 -0400517#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700518 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700519 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400520 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700521 SkDrawIter iter(this);
522
reed@google.com4e2b3d32011-04-07 14:18:59 +0000523#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000524
525////////////////////////////////////////////////////////////////////////////
526
msarettfbfa2582016-08-12 08:29:08 -0700527static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
528 if (bounds.isEmpty()) {
529 return SkRect::MakeEmpty();
530 }
531
532 // Expand bounds out by 1 in case we are anti-aliasing. We store the
533 // bounds as floats to enable a faster quick reject implementation.
534 SkRect dst;
535 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
536 return dst;
537}
538
mtkleinfeaadee2015-04-08 11:25:48 -0700539void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
540 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700541 fMCRec->reset(bounds);
542
543 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500544 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400545 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700546 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700547 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700548}
549
Hal Canary363a3f82018-10-04 11:04:48 -0400550void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000551 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800552 fSaveCount = 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553
554 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500555 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500556 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700557 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000558
reeda499f902015-05-01 09:34:31 -0700559 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
560 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400561 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700562
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000564
halcanary96fcdcc2015-08-27 07:41:13 -0700565 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000566
reedf92c8662014-08-18 08:02:43 -0700567 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700568 // The root device and the canvas should always have the same pixel geometry
569 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800570 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700571 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500572
Mike Reedc42a1cd2017-02-14 14:25:14 -0500573 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700574 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400575
Herb Derby59d997a2018-06-07 12:44:09 -0400576 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000577}
578
reed@google.comcde92112011-07-06 20:00:52 +0000579SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000580 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700581 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000582{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000583 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000584
Hal Canary363a3f82018-10-04 11:04:48 -0400585 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000586}
587
reed96a857e2015-01-25 10:33:58 -0800588SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000589 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800590 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000591{
592 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400593 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400594 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700595}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000596
Hal Canary363a3f82018-10-04 11:04:48 -0400597SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700598 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700599 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700600{
601 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700602
Mike Reed566e53c2017-03-10 10:49:45 -0500603 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400604 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700605}
606
Herb Derbyefe39bc2018-05-01 17:06:20 -0400607SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000608 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700609 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000610{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000611 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700612
Hal Canary363a3f82018-10-04 11:04:48 -0400613 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700614}
615
reed4a8126e2014-09-22 07:29:03 -0700616SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700617 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700618 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700619{
620 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700621
Mike Reed910ca0f2018-04-25 13:04:05 -0400622 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400623 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700624}
reed29c857d2014-09-21 10:25:07 -0700625
Mike Reed356f7c22017-01-10 11:58:39 -0500626SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
627 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700628 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
629 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500630 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700631{
632 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700633
Mike Reed910ca0f2018-04-25 13:04:05 -0400634 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400635 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000636}
637
Mike Reed356f7c22017-01-10 11:58:39 -0500638SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
639
Matt Sarett31f99ce2017-04-11 08:46:01 -0400640#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
641SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
642 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
643 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
644 , fAllocator(nullptr)
645{
646 inc_canvas();
647
648 SkBitmap tmp(bitmap);
649 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400650 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400651 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400652}
653#endif
654
reed@android.com8a1c16f2008-12-17 15:59:43 +0000655SkCanvas::~SkCanvas() {
656 // free up the contents of our deque
657 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000658
reed@android.com8a1c16f2008-12-17 15:59:43 +0000659 this->internalRestore(); // restore the last, since we're going away
660
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661 dec_canvas();
662}
663
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664///////////////////////////////////////////////////////////////////////////////
665
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000666void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700667 this->onFlush();
668}
669
670void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000671 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000672 if (device) {
673 device->flush();
674 }
675}
676
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000677SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000678 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000679 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
680}
681
senorblancoafc7cce2016-02-02 18:44:15 -0800682SkIRect SkCanvas::getTopLayerBounds() const {
683 SkBaseDevice* d = this->getTopDevice();
684 if (!d) {
685 return SkIRect::MakeEmpty();
686 }
687 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
688}
689
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000690SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000692 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400694 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000695}
696
Florin Malita0ed3b642017-01-13 16:56:38 +0000697SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400698 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000699}
700
Mike Reed353196f2017-07-21 11:01:18 -0400701bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000702 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400703 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000704}
705
Mike Reed353196f2017-07-21 11:01:18 -0400706bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
707 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400708}
709
710bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
711 SkPixmap pm;
712 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
713}
714
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000715bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400716 SkPixmap pm;
717 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700718 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000719 }
720 return false;
721}
722
Matt Sarett03dd6d52017-01-23 12:15:09 -0500723bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000724 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000725 SkBaseDevice* device = this->getDevice();
726 if (!device) {
727 return false;
728 }
729
Matt Sarett03dd6d52017-01-23 12:15:09 -0500730 // This check gives us an early out and prevents generation ID churn on the surface.
731 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
732 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
733 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
734 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000735 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000736
Matt Sarett03dd6d52017-01-23 12:15:09 -0500737 // Tell our owning surface to bump its generation ID.
738 const bool completeOverwrite =
739 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700740 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700741
Matt Sarett03dd6d52017-01-23 12:15:09 -0500742 // This can still fail, most notably in the case of a invalid color type or alpha type
743 // conversion. We could pull those checks into this function and avoid the unnecessary
744 // generation ID bump. But then we would be performing those checks twice, since they
745 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400746 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000747}
reed@google.com51df9e32010-12-23 19:29:18 +0000748
reed@android.com8a1c16f2008-12-17 15:59:43 +0000749//////////////////////////////////////////////////////////////////////////////
750
reed2ff1fce2014-12-11 07:07:37 -0800751void SkCanvas::checkForDeferredSave() {
752 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800753 this->doSave();
754 }
755}
756
reedf0090cb2014-11-26 08:55:51 -0800757int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800758#ifdef SK_DEBUG
759 int count = 0;
760 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
761 for (;;) {
762 const MCRec* rec = (const MCRec*)iter.next();
763 if (!rec) {
764 break;
765 }
766 count += 1 + rec->fDeferredSaveCount;
767 }
768 SkASSERT(count == fSaveCount);
769#endif
770 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800771}
772
773int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800774 fSaveCount += 1;
775 fMCRec->fDeferredSaveCount += 1;
776 return this->getSaveCount() - 1; // return our prev value
777}
778
779void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800780 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700781
782 SkASSERT(fMCRec->fDeferredSaveCount > 0);
783 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800784 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800785}
786
787void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800788 if (fMCRec->fDeferredSaveCount > 0) {
789 SkASSERT(fSaveCount > 1);
790 fSaveCount -= 1;
791 fMCRec->fDeferredSaveCount -= 1;
792 } else {
793 // check for underflow
794 if (fMCStack.count() > 1) {
795 this->willRestore();
796 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700797 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800798 this->internalRestore();
799 this->didRestore();
800 }
reedf0090cb2014-11-26 08:55:51 -0800801 }
802}
803
804void SkCanvas::restoreToCount(int count) {
805 // sanity check
806 if (count < 1) {
807 count = 1;
808 }
mtkleinf0f14112014-12-12 08:46:25 -0800809
reedf0090cb2014-11-26 08:55:51 -0800810 int n = this->getSaveCount() - count;
811 for (int i = 0; i < n; ++i) {
812 this->restore();
813 }
814}
815
reed2ff1fce2014-12-11 07:07:37 -0800816void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700818 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000819 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000820
Mike Reedc42a1cd2017-02-14 14:25:14 -0500821 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000822}
823
reed4960eee2015-12-18 07:09:18 -0800824bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400825 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000826}
827
reed4960eee2015-12-18 07:09:18 -0800828bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700829 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500830 SkIRect clipBounds = this->getDeviceClipBounds();
831 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000832 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000833 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000834
reed96e657d2015-03-10 17:30:07 -0700835 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
836
Robert Phillips12078432018-05-17 11:17:39 -0400837 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
838 // If the image filter DAG affects transparent black then we will need to render
839 // out to the clip bounds
840 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000841 }
Robert Phillips12078432018-05-17 11:17:39 -0400842
843 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700844 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700846 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400847 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000848 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400849 inputSaveLayerBounds = clipBounds;
850 }
851
852 if (imageFilter) {
853 // expand the clip bounds by the image filter DAG to include extra content that might
854 // be required by the image filters.
855 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
856 SkImageFilter::kReverse_MapDirection,
857 &inputSaveLayerBounds);
858 }
859
860 SkIRect clippedSaveLayerBounds;
861 if (bounds) {
862 // For better or for worse, user bounds currently act as a hard clip on the layer's
863 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
864 clippedSaveLayerBounds = inputSaveLayerBounds;
865 } else {
866 // If there are no user bounds, we don't want to artificially restrict the resulting
867 // layer bounds, so allow the expanded clip bounds free reign.
868 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000869 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800870
871 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400872 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800873 if (BoundsAffectsClip(saveLayerFlags)) {
874 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
875 fMCRec->fRasterClip.setEmpty();
876 fDeviceClipBounds.setEmpty();
877 }
878 return false;
879 }
Robert Phillips12078432018-05-17 11:17:39 -0400880 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000881
reed4960eee2015-12-18 07:09:18 -0800882 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700883 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400884 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
885 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000886 }
887
888 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400889 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000890 }
Robert Phillips12078432018-05-17 11:17:39 -0400891
junov@chromium.orga907ac32012-02-24 21:54:07 +0000892 return true;
893}
894
reed4960eee2015-12-18 07:09:18 -0800895int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
896 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000897}
898
Cary Clarke041e312018-03-06 13:00:52 -0500899int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700900 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400901 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
902 // no need for the layer (or any of the draws until the matching restore()
903 this->save();
904 this->clipRect({0,0,0,0});
905 } else {
906 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
907 fSaveCount += 1;
908 this->internalSaveLayer(rec, strategy);
909 }
reed4960eee2015-12-18 07:09:18 -0800910 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800911}
912
Mike Reed148b7fd2018-12-18 17:38:18 -0500913int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
914 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
915 // Assuming clips never expand, if the request bounds is outside of the current clip
916 // there is no need to copy/restore the area, so just devolve back to a regular save.
917 this->save();
918 } else {
919 bool doTheWork = this->onDoSaveBehind(bounds);
920 fSaveCount += 1;
921 this->internalSave();
922 if (doTheWork) {
923 this->internalSaveBehind(bounds);
924 }
925 }
926 return this->getSaveCount() - 1;
927}
928
reeda2217ef2016-07-20 06:04:34 -0700929void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500930 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500931 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700932 SkDraw draw;
933 SkRasterClip rc;
934 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
935 if (!dst->accessPixels(&draw.fDst)) {
936 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800937 }
reeda2217ef2016-07-20 06:04:34 -0700938 draw.fMatrix = &SkMatrix::I();
939 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800940
941 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500942 if (filter) {
943 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
944 }
reeda2217ef2016-07-20 06:04:34 -0700945
Mike Reedc42a1cd2017-02-14 14:25:14 -0500946 int x = src->getOrigin().x() - dstOrigin.x();
947 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700948 auto special = src->snapSpecial();
949 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400950 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700951 }
robertphillips7354a4b2015-12-16 05:08:27 -0800952}
reed70ee31b2015-12-10 13:44:45 -0800953
Mike Reed25394292019-03-07 09:36:36 -0500954// This is shared by all backends, but contains raster-specific thoughts. Can we defer to the
955// device to perform this?
Mike Kleine083f7c2018-02-07 12:54:27 -0500956static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500957 // Need to force L32 for now if we have an image filter.
Mike Reed25394292019-03-07 09:36:36 -0500958 // If filters ever support other colortypes, e.g. F16, we can modify this check.
Mike Klein649fb732018-02-26 15:09:16 -0500959 if (paint && paint->getImageFilter()) {
Mike Reed25394292019-03-07 09:36:36 -0500960 // TODO: can we query the imagefilter, to see if it can handle floats (so we don't always
961 // use N32 when the layer itself was float)?
962 return SkImageInfo::MakeN32Premul(w, h, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800963 }
Mike Klein649fb732018-02-26 15:09:16 -0500964
965 SkColorType ct = prev.colorType();
966 if (prev.bytesPerPixel() <= 4) {
967 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
968 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
969 ct = kN32_SkColorType;
970 }
971 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800972}
973
reed4960eee2015-12-18 07:09:18 -0800974void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700975 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800976 const SkRect* bounds = rec.fBounds;
977 const SkPaint* paint = rec.fPaint;
978 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
979
Mike Reed5532c2a2019-02-23 12:00:32 -0500980 // If we have a backdrop filter, then we must apply it to the entire layer (clip-bounds)
981 // regardless of any hint-rect from the caller. skbug.com/8783
982 if (rec.fBackdrop) {
983 bounds = nullptr;
984 }
985
reed8c30a812016-04-20 16:36:51 -0700986 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400987 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700988 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400989 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700990 SkMatrix remainder;
991 SkSize scale;
992 /*
993 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
994 * but they do handle scaling. To accommodate this, we do the following:
995 *
996 * 1. Stash off the current CTM
997 * 2. Decompose the CTM into SCALE and REMAINDER
998 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
999 * contains the REMAINDER
1000 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1001 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1002 * of the original imagefilter, and draw that (via drawSprite)
1003 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1004 *
1005 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1006 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1007 */
reed96a04f32016-04-25 09:25:15 -07001008 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001009 stashedMatrix.decomposeScale(&scale, &remainder))
1010 {
1011 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001012 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001013 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1014 SkPaint* p = lazyP.set(*paint);
1015 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1016 SkFilterQuality::kLow_SkFilterQuality,
1017 sk_ref_sp(imageFilter)));
1018 imageFilter = p->getImageFilter();
1019 paint = p;
1020 }
reed8c30a812016-04-20 16:36:51 -07001021
junov@chromium.orga907ac32012-02-24 21:54:07 +00001022 // do this before we create the layer. We don't call the public save() since
1023 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001024 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001025
junov@chromium.orga907ac32012-02-24 21:54:07 +00001026 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001027 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001028 if (modifiedRec) {
1029 // In this case there will be no layer in which to stash the matrix so we need to
1030 // revert the prior MCRec to its earlier state.
1031 modifiedRec->fMatrix = stashedMatrix;
1032 }
reed2ff1fce2014-12-11 07:07:37 -08001033 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001034 }
1035
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001036 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1037 // the clipRectBounds() call above?
1038 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001039 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001040 }
1041
reed8dc0ccb2015-03-20 06:32:52 -07001042 SkPixelGeometry geo = fProps.pixelGeometry();
1043 if (paint) {
reed76033be2015-03-14 10:54:31 -07001044 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001045 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001046 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001047 }
1048 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001049
robertphillips5139e502016-07-19 05:10:40 -07001050 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001051 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001052 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001053 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001054 }
reedb2db8982014-11-13 12:41:02 -08001055
Mike Kleine083f7c2018-02-07 12:54:27 -05001056 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001057
Hal Canary704cd322016-11-07 14:13:52 -05001058 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001059 {
Florin Malita07e4adf2019-01-07 16:34:18 -05001060 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType();
reeddaa57bf2015-05-15 10:39:17 -07001061 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001062 const bool trackCoverage =
1063 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001064 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001065 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001066 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001067 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001068 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1069 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001070 return;
reed61f501f2015-04-29 08:34:00 -07001071 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001072 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001073 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001074
Mike Reedb43a3e02017-02-11 10:18:58 -05001075 // only have a "next" if this new layer doesn't affect the clip (rare)
1076 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001077 fMCRec->fLayer = layer;
1078 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001079
Mike Reedc61abee2017-02-28 17:45:27 -05001080 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001081 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001082 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001083 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001084
Mike Reedc42a1cd2017-02-14 14:25:14 -05001085 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1086
1087 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1088 if (layer->fNext) {
1089 // need to punch a hole in the previous device, so we don't draw there, given that
1090 // the new top-layer will allow drawing to happen "below" it.
1091 SkRegion hole(ir);
1092 do {
1093 layer = layer->fNext;
1094 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1095 } while (layer->fNext);
1096 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001097}
1098
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001099int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001100 if (0xFF == alpha) {
1101 return this->saveLayer(bounds, nullptr);
1102 } else {
1103 SkPaint tmpPaint;
1104 tmpPaint.setAlpha(alpha);
1105 return this->saveLayer(bounds, &tmpPaint);
1106 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001107}
1108
Mike Reed148b7fd2018-12-18 17:38:18 -05001109void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1110 SkIRect devBounds;
1111 if (localBounds) {
1112 SkRect tmp;
1113 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1114 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1115 devBounds.setEmpty();
1116 }
1117 } else {
1118 devBounds = this->getDeviceClipBounds();
1119 }
1120 if (devBounds.isEmpty()) {
1121 return;
1122 }
1123
1124 SkBaseDevice* device = this->getTopDevice();
1125 if (nullptr == device) { // Do we still need this check???
1126 return;
1127 }
1128
1129 // need the bounds relative to the device itself
1130 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1131
1132 auto backImage = device->snapBackImage(devBounds);
1133 if (!backImage) {
1134 return;
1135 }
1136
1137 // we really need the save, so we can wack the fMCRec
1138 this->checkForDeferredSave();
1139
1140 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1141
1142 SkPaint paint;
1143 paint.setBlendMode(SkBlendMode::kClear);
Mike Reed9adc82c2019-04-23 10:28:13 -04001144 this->drawClippedToSaveBehind(paint);
Mike Reed148b7fd2018-12-18 17:38:18 -05001145}
1146
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147void SkCanvas::internalRestore() {
1148 SkASSERT(fMCStack.count() != 0);
1149
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001150 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001151 DeviceCM* layer = fMCRec->fLayer; // may be null
1152 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001153 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001154
Mike Reed148b7fd2018-12-18 17:38:18 -05001155 // move this out before we do the actual restore
1156 auto backImage = std::move(fMCRec->fBackImage);
1157
reed@android.com8a1c16f2008-12-17 15:59:43 +00001158 // now do the normal restore()
1159 fMCRec->~MCRec(); // balanced in save()
1160 fMCStack.pop_back();
1161 fMCRec = (MCRec*)fMCStack.back();
1162
Mike Reedc42a1cd2017-02-14 14:25:14 -05001163 if (fMCRec) {
1164 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1165 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001166
Mike Reed148b7fd2018-12-18 17:38:18 -05001167 if (backImage) {
1168 SkPaint paint;
1169 paint.setBlendMode(SkBlendMode::kDstOver);
1170 const int x = backImage->fLoc.x();
1171 const int y = backImage->fLoc.y();
1172 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1173 nullptr, SkMatrix::I());
1174 }
1175
reed@android.com8a1c16f2008-12-17 15:59:43 +00001176 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1177 since if we're being recorded, we don't want to record this (the
1178 recorder will have already recorded the restore).
1179 */
bsalomon49f085d2014-09-05 13:34:00 -07001180 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001181 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001182 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001183 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001184 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001185 layer->fPaint.get(),
1186 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001187 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001188 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001189 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001190 delete layer;
reedb679ca82015-04-07 04:40:48 -07001191 } else {
1192 // we're at the root
reeda499f902015-05-01 09:34:31 -07001193 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001194 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001195 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001196 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001197 }
msarettfbfa2582016-08-12 08:29:08 -07001198
1199 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001200 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001201 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1202 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001203}
1204
reede8f30622016-03-23 18:59:25 -07001205sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001206 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001207 props = &fProps;
1208 }
1209 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001210}
1211
reede8f30622016-03-23 18:59:25 -07001212sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001213 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001214 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001215}
1216
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001217SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001218 return this->onImageInfo();
1219}
1220
1221SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001222 SkBaseDevice* dev = this->getDevice();
1223 if (dev) {
1224 return dev->imageInfo();
1225 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001226 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001227 }
1228}
1229
brianosman898235c2016-04-06 07:38:23 -07001230bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001231 return this->onGetProps(props);
1232}
1233
1234bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001235 SkBaseDevice* dev = this->getDevice();
1236 if (dev) {
1237 if (props) {
1238 *props = fProps;
1239 }
1240 return true;
1241 } else {
1242 return false;
1243 }
1244}
1245
reed6ceeebd2016-03-09 14:26:26 -08001246bool SkCanvas::peekPixels(SkPixmap* pmap) {
1247 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001248}
1249
reed884e97c2015-05-26 11:31:54 -07001250bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001251 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001252 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001253}
1254
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001255void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001256 SkPixmap pmap;
1257 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001258 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001259 }
1260 if (info) {
1261 *info = pmap.info();
1262 }
1263 if (rowBytes) {
1264 *rowBytes = pmap.rowBytes();
1265 }
1266 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001267 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001268 }
reed884e97c2015-05-26 11:31:54 -07001269 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001270}
1271
reed884e97c2015-05-26 11:31:54 -07001272bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001273 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001274 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001275}
1276
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278
Mike Reed8bcd1282019-03-13 16:51:54 -04001279// In our current design/features, we should never have a layer (src) in a different colorspace
1280// than its parent (dst), so we assert that here. This is called out from other asserts, in case
1281// we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1282// colorspace.
1283static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1284 SkASSERT(src == dst);
1285}
1286
Florin Malita53f77bd2017-04-28 13:48:37 -04001287void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1288 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001290 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291 paint = &tmp;
1292 }
reed@google.com4b226022011-01-11 18:32:13 +00001293
Ben Wagner2c312c42018-06-27 14:46:46 -04001294 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001295
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001297 SkBaseDevice* dstDev = iter.fDevice;
Mike Reed8bcd1282019-03-13 16:51:54 -04001298 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1299 srcDev->imageInfo().colorSpace());
reed@google.com76dd2772012-01-05 21:15:07 +00001300 paint = &looper.paint();
1301 SkImageFilter* filter = paint->getImageFilter();
1302 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001303 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001304 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1305 if (specialImage) {
Mike Reed8bcd1282019-03-13 16:51:54 -04001306 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1307 specialImage->getColorSpace());
Florin Malita53f77bd2017-04-28 13:48:37 -04001308 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1309 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001310 }
reed@google.com76dd2772012-01-05 21:15:07 +00001311 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001312 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001313 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314 }
reeda2217ef2016-07-20 06:04:34 -07001315
reed@google.com4e2b3d32011-04-07 14:18:59 +00001316 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317}
1318
reed32704672015-12-16 08:27:10 -08001319/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001320
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001321void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001322 if (dx || dy) {
1323 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001324 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001325
reedfe69b502016-09-12 06:31:48 -07001326 // Translate shouldn't affect the is-scale-translateness of the matrix.
1327 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001328
Mike Reedc42a1cd2017-02-14 14:25:14 -05001329 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001330
reedfe69b502016-09-12 06:31:48 -07001331 this->didTranslate(dx,dy);
1332 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333}
1334
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001335void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001336 SkMatrix m;
1337 m.setScale(sx, sy);
1338 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339}
1340
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001341void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001342 SkMatrix m;
1343 m.setRotate(degrees);
1344 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001345}
1346
bungeman7438bfc2016-07-12 15:01:19 -07001347void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1348 SkMatrix m;
1349 m.setRotate(degrees, px, py);
1350 this->concat(m);
1351}
1352
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001353void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001354 SkMatrix m;
1355 m.setSkew(sx, sy);
1356 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001357}
1358
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001359void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001360 if (matrix.isIdentity()) {
1361 return;
1362 }
1363
reed2ff1fce2014-12-11 07:07:37 -08001364 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001365 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001366 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001367
Mike Reed7627fa52017-02-08 10:07:53 -05001368 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001369
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001370 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001371}
1372
reed8c30a812016-04-20 16:36:51 -07001373void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001374 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001375 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001376
Mike Reedc42a1cd2017-02-14 14:25:14 -05001377 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001378}
1379
1380void SkCanvas::setMatrix(const SkMatrix& matrix) {
1381 this->checkForDeferredSave();
1382 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001383 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001384}
1385
reed@android.com8a1c16f2008-12-17 15:59:43 +00001386void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001387 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001388}
1389
1390//////////////////////////////////////////////////////////////////////////////
1391
Mike Reedc1f77742016-12-09 09:00:50 -05001392void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001393 if (!rect.isFinite()) {
1394 return;
1395 }
reed2ff1fce2014-12-11 07:07:37 -08001396 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001397 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1398 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001399}
1400
Mike Reedc1f77742016-12-09 09:00:50 -05001401void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001402 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001403
Mike Reed7627fa52017-02-08 10:07:53 -05001404 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001405
reedc64eff52015-11-21 12:39:45 -08001406 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001407 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1408 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001409 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001410}
1411
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001412void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1413 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001414 if (fClipRestrictionRect.isEmpty()) {
1415 // we notify the device, but we *dont* resolve deferred saves (since we're just
1416 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001417 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001418 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001419 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001420 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001421 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001422 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001423 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1424 }
1425}
1426
Mike Reedc1f77742016-12-09 09:00:50 -05001427void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001428 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001429 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001430 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001431 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1432 } else {
1433 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001434 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001435}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001436
Mike Reedc1f77742016-12-09 09:00:50 -05001437void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001438 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001439
Brian Salomona3b45d42016-10-03 11:36:16 -04001440 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001441
Mike Reed7627fa52017-02-08 10:07:53 -05001442 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001443
Mike Reed20800c82017-11-15 16:09:04 -05001444 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1445 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001446 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001447}
1448
Mike Reedc1f77742016-12-09 09:00:50 -05001449void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001450 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001451 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001452
1453 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1454 SkRect r;
1455 if (path.isRect(&r)) {
1456 this->onClipRect(r, op, edgeStyle);
1457 return;
1458 }
1459 SkRRect rrect;
1460 if (path.isOval(&r)) {
1461 rrect.setOval(r);
1462 this->onClipRRect(rrect, op, edgeStyle);
1463 return;
1464 }
1465 if (path.isRRect(&rrect)) {
1466 this->onClipRRect(rrect, op, edgeStyle);
1467 return;
1468 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001469 }
robertphillips39f05382015-11-24 09:30:12 -08001470
1471 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001472}
1473
Mike Reedc1f77742016-12-09 09:00:50 -05001474void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001475 AutoValidateClip avc(this);
1476
Brian Salomona3b45d42016-10-03 11:36:16 -04001477 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001478
Mike Reed7627fa52017-02-08 10:07:53 -05001479 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001480
Brian Salomona3b45d42016-10-03 11:36:16 -04001481 const SkPath* rasterClipPath = &path;
1482 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001483 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1484 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001485 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001486}
1487
Mike Reedc1f77742016-12-09 09:00:50 -05001488void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001489 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001490 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001491}
1492
Mike Reedc1f77742016-12-09 09:00:50 -05001493void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001494 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001495
reed@google.com5c3d1472011-02-22 19:12:23 +00001496 AutoValidateClip avc(this);
1497
Mike Reed20800c82017-11-15 16:09:04 -05001498 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001499 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001500}
1501
reed@google.com819c9212011-02-23 18:56:55 +00001502#ifdef SK_DEBUG
1503void SkCanvas::validateClip() const {
1504 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001505 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001506 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001507 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001508 return;
1509 }
reed@google.com819c9212011-02-23 18:56:55 +00001510}
1511#endif
1512
Mike Reeda1361362017-03-07 09:37:29 -05001513bool SkCanvas::androidFramework_isClipAA() const {
1514 bool containsAA = false;
1515
1516 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1517
1518 return containsAA;
1519}
1520
1521class RgnAccumulator {
1522 SkRegion* fRgn;
1523public:
1524 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1525 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1526 SkIPoint origin = device->getOrigin();
1527 if (origin.x() | origin.y()) {
1528 rgn->translate(origin.x(), origin.y());
1529 }
1530 fRgn->op(*rgn, SkRegion::kUnion_Op);
1531 }
1532};
1533
1534void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1535 RgnAccumulator accum(rgn);
1536 SkRegion tmp;
1537
1538 rgn->setEmpty();
1539 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001540}
1541
reed@google.com5c3d1472011-02-22 19:12:23 +00001542///////////////////////////////////////////////////////////////////////////////
1543
reed@google.com754de5f2014-02-24 19:38:20 +00001544bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001545 return fMCRec->fRasterClip.isEmpty();
1546
1547 // TODO: should we only use the conservative answer in a recording canvas?
1548#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001549 SkBaseDevice* dev = this->getTopDevice();
1550 // if no device we return true
1551 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001552#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001553}
1554
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001555bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001556 SkBaseDevice* dev = this->getTopDevice();
1557 // if no device we return false
1558 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001559}
1560
msarettfbfa2582016-08-12 08:29:08 -07001561static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1562#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1563 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1564 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1565 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1566 return 0xF != _mm_movemask_ps(mask);
1567#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1568 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1569 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1570 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1571 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1572#else
1573 SkRect devRectAsRect;
1574 SkRect devClipAsRect;
1575 devRect.store(&devRectAsRect.fLeft);
1576 devClip.store(&devClipAsRect.fLeft);
1577 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1578#endif
1579}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001580
msarettfbfa2582016-08-12 08:29:08 -07001581// It's important for this function to not be inlined. Otherwise the compiler will share code
1582// between the fast path and the slow path, resulting in two slow paths.
1583static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1584 const SkMatrix& matrix) {
1585 SkRect deviceRect;
1586 matrix.mapRect(&deviceRect, src);
1587 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1588}
1589
1590bool SkCanvas::quickReject(const SkRect& src) const {
1591#ifdef SK_DEBUG
1592 // Verify that fDeviceClipBounds are set properly.
1593 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001594 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001595 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001596 } else {
msarettfbfa2582016-08-12 08:29:08 -07001597 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001598 }
msarettfbfa2582016-08-12 08:29:08 -07001599
msarett9637ea92016-08-18 14:03:30 -07001600 // Verify that fIsScaleTranslate is set properly.
1601 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001602#endif
1603
msarett9637ea92016-08-18 14:03:30 -07001604 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001605 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1606 }
1607
1608 // We inline the implementation of mapScaleTranslate() for the fast path.
1609 float sx = fMCRec->fMatrix.getScaleX();
1610 float sy = fMCRec->fMatrix.getScaleY();
1611 float tx = fMCRec->fMatrix.getTranslateX();
1612 float ty = fMCRec->fMatrix.getTranslateY();
1613 Sk4f scale(sx, sy, sx, sy);
1614 Sk4f trans(tx, ty, tx, ty);
1615
1616 // Apply matrix.
1617 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1618
1619 // Make sure left < right, top < bottom.
1620 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1621 Sk4f min = Sk4f::Min(ltrb, rblt);
1622 Sk4f max = Sk4f::Max(ltrb, rblt);
1623 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1624 // ARM this sequence generates the fastest (a single instruction).
1625 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1626
1627 // Check if the device rect is NaN or outside the clip.
1628 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001629}
1630
reed@google.com3b3e8952012-08-16 20:53:31 +00001631bool SkCanvas::quickReject(const SkPath& path) const {
1632 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001633}
1634
Mike Klein83c8dd92017-11-28 17:08:45 -05001635SkRect SkCanvas::getLocalClipBounds() const {
1636 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001637 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001638 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001639 }
1640
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001641 SkMatrix inverse;
1642 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001643 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001644 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001645 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001646
Mike Reed42e8c532017-01-23 14:09:13 -05001647 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001648 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001649 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001650
Mike Reedb57b9312018-04-23 12:12:54 -04001651 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001652 inverse.mapRect(&bounds, r);
1653 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001654}
1655
Mike Klein83c8dd92017-11-28 17:08:45 -05001656SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001657 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001658}
1659
reed@android.com8a1c16f2008-12-17 15:59:43 +00001660const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001661 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001662}
1663
Brian Osman11052242016-10-27 14:47:55 -04001664GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001665 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001666 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001667}
1668
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001669GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001670 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001671 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001672}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001673
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001674void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1675 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001676 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001677 if (outer.isEmpty()) {
1678 return;
1679 }
1680 if (inner.isEmpty()) {
1681 this->drawRRect(outer, paint);
1682 return;
1683 }
1684
1685 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001686 // be able to return ...
1687 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001688 //
1689 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001690 if (!outer.getBounds().contains(inner.getBounds())) {
1691 return;
1692 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001693
1694 this->onDrawDRRect(outer, inner, paint);
1695}
1696
reed41af9662015-01-05 07:49:08 -08001697void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001698 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001699 this->onDrawPaint(paint);
1700}
1701
1702void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001703 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001704 // To avoid redundant logic in our culling code and various backends, we always sort rects
1705 // before passing them along.
1706 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001707}
1708
Mike Reedd5674082019-04-19 15:00:47 -04001709void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1710 TRACE_EVENT0("skia", TRACE_FUNC);
1711 this->onDrawBehind(paint);
1712}
1713
msarettdca352e2016-08-26 06:37:45 -07001714void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001715 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001716 if (region.isEmpty()) {
1717 return;
1718 }
1719
1720 if (region.isRect()) {
1721 return this->drawIRect(region.getBounds(), paint);
1722 }
1723
1724 this->onDrawRegion(region, paint);
1725}
1726
reed41af9662015-01-05 07:49:08 -08001727void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001728 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001729 // To avoid redundant logic in our culling code and various backends, we always sort rects
1730 // before passing them along.
1731 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001732}
1733
1734void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001735 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001736 this->onDrawRRect(rrect, paint);
1737}
1738
1739void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001740 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001741 this->onDrawPoints(mode, count, pts, paint);
1742}
1743
Mike Reede88a1cb2017-03-17 09:50:46 -04001744void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1745 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001746 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001747 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001748 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1749 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001750 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001751}
1752
1753void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001754 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001755 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001756 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1757}
1758
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001759void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1760 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001761 TRACE_EVENT0("skia", TRACE_FUNC);
1762 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001763 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001764 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1765}
1766
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001767void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1768 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001769 TRACE_EVENT0("skia", TRACE_FUNC);
1770 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001771 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001772 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001773}
1774
1775void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001776 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001777 this->onDrawPath(path, paint);
1778}
1779
reeda85d4d02015-05-06 12:56:48 -07001780void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001781 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001782 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001783 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001784}
1785
Mike Reedc4e31092018-01-30 11:15:27 -05001786// Returns true if the rect can be "filled" : non-empty and finite
1787static bool fillable(const SkRect& r) {
1788 SkScalar w = r.width();
1789 SkScalar h = r.height();
1790 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1791}
1792
reede47829b2015-08-06 10:02:53 -07001793void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1794 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001795 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001796 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001797 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001798 return;
1799 }
1800 this->onDrawImageRect(image, &src, dst, paint, constraint);
1801}
reed41af9662015-01-05 07:49:08 -08001802
reed84984ef2015-07-17 07:09:43 -07001803void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1804 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001805 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001806 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001807}
1808
Brian Salomonf08002c2018-10-26 16:15:46 -04001809void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001810 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001811 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001812 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001813}
reede47829b2015-08-06 10:02:53 -07001814
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001815namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001816class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001817public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001818 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1819 if (!origPaint) {
1820 return;
1821 }
1822 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1823 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1824 }
1825 if (origPaint->getMaskFilter()) {
1826 fPaint.writable()->setMaskFilter(nullptr);
1827 }
1828 if (origPaint->isAntiAlias()) {
1829 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001830 }
1831 }
1832
1833 const SkPaint* get() const {
1834 return fPaint;
1835 }
1836
1837private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001838 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001839};
1840} // namespace
1841
reed4c21dc52015-06-25 12:32:03 -07001842void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1843 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001844 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001845 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001846 if (dst.isEmpty()) {
1847 return;
1848 }
msarett552bca92016-08-03 06:53:26 -07001849 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001850 LatticePaint latticePaint(paint);
1851 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001852 } else {
reede47829b2015-08-06 10:02:53 -07001853 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001854 }
reed4c21dc52015-06-25 12:32:03 -07001855}
1856
msarett16882062016-08-16 09:31:08 -07001857void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1858 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001859 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001860 RETURN_ON_NULL(image);
1861 if (dst.isEmpty()) {
1862 return;
1863 }
msarett71df2d72016-09-30 12:41:42 -07001864
1865 SkIRect bounds;
1866 Lattice latticePlusBounds = lattice;
1867 if (!latticePlusBounds.fBounds) {
1868 bounds = SkIRect::MakeWH(image->width(), image->height());
1869 latticePlusBounds.fBounds = &bounds;
1870 }
1871
1872 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001873 LatticePaint latticePaint(paint);
1874 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001875 } else {
1876 this->drawImageRect(image, dst, paint);
1877 }
1878}
1879
reed41af9662015-01-05 07:49:08 -08001880void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001881 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001882 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001883 return;
1884 }
reed41af9662015-01-05 07:49:08 -08001885 this->onDrawBitmap(bitmap, dx, dy, paint);
1886}
1887
reede47829b2015-08-06 10:02:53 -07001888void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001889 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001890 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001891 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001892 return;
1893 }
reede47829b2015-08-06 10:02:53 -07001894 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001895}
1896
reed84984ef2015-07-17 07:09:43 -07001897void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1898 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001899 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001900}
1901
reede47829b2015-08-06 10:02:53 -07001902void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1903 SrcRectConstraint constraint) {
1904 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1905 constraint);
1906}
reede47829b2015-08-06 10:02:53 -07001907
reed41af9662015-01-05 07:49:08 -08001908void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1909 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001910 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001911 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001912 return;
1913 }
msarett552bca92016-08-03 06:53:26 -07001914 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001915 LatticePaint latticePaint(paint);
1916 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001917 } else {
reeda5517e22015-07-14 10:54:12 -07001918 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001919 }
reed41af9662015-01-05 07:49:08 -08001920}
1921
msarettc573a402016-08-02 08:05:56 -07001922void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1923 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001924 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001925 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001926 return;
1927 }
msarett71df2d72016-09-30 12:41:42 -07001928
1929 SkIRect bounds;
1930 Lattice latticePlusBounds = lattice;
1931 if (!latticePlusBounds.fBounds) {
1932 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1933 latticePlusBounds.fBounds = &bounds;
1934 }
1935
1936 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001937 LatticePaint latticePaint(paint);
1938 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001939 } else {
msarett16882062016-08-16 09:31:08 -07001940 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001941 }
msarettc573a402016-08-02 08:05:56 -07001942}
1943
reed71c3c762015-06-24 10:29:17 -07001944void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001945 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001946 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001947 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001948 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001949 if (count <= 0) {
1950 return;
1951 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001952 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001953 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001954 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001955}
1956
reedf70b5312016-03-04 16:36:20 -08001957void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001958 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001959 if (key) {
1960 this->onDrawAnnotation(rect, key, value);
1961 }
1962}
1963
reede47829b2015-08-06 10:02:53 -07001964void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1965 const SkPaint* paint, SrcRectConstraint constraint) {
1966 if (src) {
1967 this->drawImageRect(image, *src, dst, paint, constraint);
1968 } else {
1969 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1970 dst, paint, constraint);
1971 }
1972}
1973void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1974 const SkPaint* paint, SrcRectConstraint constraint) {
1975 if (src) {
1976 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1977 } else {
1978 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1979 dst, paint, constraint);
1980 }
1981}
1982
Mike Reed4204da22017-05-17 08:53:36 -04001983void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001984 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001985 this->onDrawShadowRec(path, rec);
1986}
1987
1988void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1989 SkPaint paint;
1990 const SkRect& pathBounds = path.getBounds();
1991
Ben Wagner2c312c42018-06-27 14:46:46 -04001992 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001993 while (iter.next()) {
1994 iter.fDevice->drawShadow(path, rec);
1995 }
1996 LOOPER_END
1997}
1998
Michael Ludwig390f0cc2019-03-19 09:16:38 -04001999void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
2000 QuadAAFlags aaFlags, SkColor color, SkBlendMode mode) {
2001 TRACE_EVENT0("skia", TRACE_FUNC);
2002 // Make sure the rect is sorted before passing it along
2003 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
2004}
2005
2006void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
2007 const SkPoint dstClips[],
2008 const SkMatrix preViewMatrices[],
2009 const SkPaint* paint,
2010 SrcRectConstraint constraint) {
2011 TRACE_EVENT0("skia", TRACE_FUNC);
2012 this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
2013}
2014
reed@android.com8a1c16f2008-12-17 15:59:43 +00002015//////////////////////////////////////////////////////////////////////////////
2016// These are the virtual drawing methods
2017//////////////////////////////////////////////////////////////////////////////
2018
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002019void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002020 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002021 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2022 }
2023}
2024
reed41af9662015-01-05 07:49:08 -08002025void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002026 this->internalDrawPaint(paint);
2027}
2028
2029void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002030 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002031
2032 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002033 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002034 }
2035
reed@google.com4e2b3d32011-04-07 14:18:59 +00002036 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002037}
2038
reed41af9662015-01-05 07:49:08 -08002039void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2040 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002041 if ((long)count <= 0) {
2042 return;
2043 }
2044
Mike Reed822128b2017-02-28 16:41:03 -05002045 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002046 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002047 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002048 // special-case 2 points (common for drawing a single line)
2049 if (2 == count) {
2050 r.set(pts[0], pts[1]);
2051 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002052 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002053 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002054 if (!r.isFinite()) {
2055 return;
2056 }
Mike Reed822128b2017-02-28 16:41:03 -05002057 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002058 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2059 return;
2060 }
2061 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002062 }
reed@google.coma584aed2012-05-16 14:06:02 +00002063
halcanary96fcdcc2015-08-27 07:41:13 -07002064 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002065
Ben Wagner2c312c42018-06-27 14:46:46 -04002066 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002067
reed@android.com8a1c16f2008-12-17 15:59:43 +00002068 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002069 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002070 }
reed@google.com4b226022011-01-11 18:32:13 +00002071
reed@google.com4e2b3d32011-04-07 14:18:59 +00002072 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002073}
2074
reed4a167172016-08-18 17:15:25 -07002075static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2076 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07002077 (intptr_t)paint.getLooper() ) != 0;
2078}
2079
reed41af9662015-01-05 07:49:08 -08002080void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002081 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002082 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002083 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002084 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002085 return;
2086 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002087 }
reed@google.com4b226022011-01-11 18:32:13 +00002088
reed4a167172016-08-18 17:15:25 -07002089 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002090 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002091
reed4a167172016-08-18 17:15:25 -07002092 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002093 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002094 }
2095
2096 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002097 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002098 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002099 SkDrawIter iter(this);
2100 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002101 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002102 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002103 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002104}
2105
msarett44df6512016-08-25 13:54:30 -07002106void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002107 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002108 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002109 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002110 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2111 return;
2112 }
msarett44df6512016-08-25 13:54:30 -07002113 }
2114
Ben Wagner2c312c42018-06-27 14:46:46 -04002115 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002116
2117 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002118 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002119 }
2120
2121 LOOPER_END
2122}
2123
Mike Reedd5674082019-04-19 15:00:47 -04002124void SkCanvas::onDrawBehind(const SkPaint& paint) {
2125 SkIRect bounds;
2126 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2127 for (;;) {
2128 const MCRec* rec = (const MCRec*)iter.prev();
2129 if (!rec) {
2130 return; // no backimages, so nothing to draw
2131 }
2132 if (rec->fBackImage) {
2133 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2134 rec->fBackImage->fImage->width(),
2135 rec->fBackImage->fImage->height());
2136 break;
2137 }
2138 }
2139
2140 LOOPER_BEGIN(paint, nullptr)
2141
2142 while (iter.next()) {
2143 SkBaseDevice* dev = iter.fDevice;
2144
Mike Reedd5674082019-04-19 15:00:47 -04002145 dev->save();
2146 // We use clipRegion because it is already defined to operate in dev-space
2147 // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2148 // but we don't want that, so we undo that before calling in.
2149 SkRegion rgn(bounds.makeOffset(dev->fOrigin.fX, dev->fOrigin.fY));
2150 dev->clipRegion(rgn, SkClipOp::kIntersect);
2151 dev->drawPaint(looper.paint());
Mike Reed9adc82c2019-04-23 10:28:13 -04002152 dev->restore(fMCRec->fMatrix);
Mike Reedd5674082019-04-19 15:00:47 -04002153 }
2154
2155 LOOPER_END
2156}
2157
reed41af9662015-01-05 07:49:08 -08002158void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002159 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002160 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002161 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002162 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002163 return;
2164 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002165 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002166
Ben Wagner2c312c42018-06-27 14:46:46 -04002167 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002168
2169 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002170 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002171 }
2172
2173 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002174}
2175
bsalomonac3aa242016-08-19 11:25:19 -07002176void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2177 SkScalar sweepAngle, bool useCenter,
2178 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002179 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002180 if (paint.canComputeFastBounds()) {
2181 SkRect storage;
2182 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002183 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002184 return;
2185 }
bsalomonac3aa242016-08-19 11:25:19 -07002186 }
2187
Ben Wagner2c312c42018-06-27 14:46:46 -04002188 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002189
2190 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002191 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002192 }
2193
2194 LOOPER_END
2195}
2196
reed41af9662015-01-05 07:49:08 -08002197void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002198 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002199 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002200 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2201 return;
2202 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002203 }
2204
2205 if (rrect.isRect()) {
2206 // call the non-virtual version
2207 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002208 return;
2209 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002210 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002211 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2212 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002213 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002214
Ben Wagner2c312c42018-06-27 14:46:46 -04002215 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002216
2217 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002218 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002219 }
2220
2221 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002222}
2223
Mike Reed822128b2017-02-28 16:41:03 -05002224void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002225 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002226 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002227 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2228 return;
2229 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002230 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002231
Ben Wagner2c312c42018-06-27 14:46:46 -04002232 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002233
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002234 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002235 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002236 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002237
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002238 LOOPER_END
2239}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002240
reed41af9662015-01-05 07:49:08 -08002241void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002242 if (!path.isFinite()) {
2243 return;
2244 }
2245
Mike Reed822128b2017-02-28 16:41:03 -05002246 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002247 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002248 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002249 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2250 return;
2251 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002252 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002253
Mike Reed822128b2017-02-28 16:41:03 -05002254 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002255 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002256 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002257 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002258 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002259 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002260
Ben Wagner2c312c42018-06-27 14:46:46 -04002261 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002262
2263 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002264 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002265 }
2266
reed@google.com4e2b3d32011-04-07 14:18:59 +00002267 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002268}
2269
reed262a71b2015-12-05 13:07:27 -08002270bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002271 if (!paint.getImageFilter()) {
2272 return false;
2273 }
2274
2275 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002276 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002277 return false;
2278 }
2279
2280 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2281 // Once we can filter and the filter will return a result larger than itself, we should be
2282 // able to remove this constraint.
2283 // skbug.com/4526
2284 //
2285 SkPoint pt;
2286 ctm.mapXY(x, y, &pt);
2287 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2288 return ir.contains(fMCRec->fRasterClip.getBounds());
2289}
2290
Mike Reedf441cfc2018-04-11 14:50:16 -04002291// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2292// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2293// null.
2294static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2295 if (paintParam) {
2296 *real = *paintParam;
2297 real->setStyle(SkPaint::kFill_Style);
2298 real->setPathEffect(nullptr);
2299 paintParam = real;
2300 }
2301 return paintParam;
2302}
2303
reeda85d4d02015-05-06 12:56:48 -07002304void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002305 SkPaint realPaint;
2306 paint = init_image_paint(&realPaint, paint);
2307
reeda85d4d02015-05-06 12:56:48 -07002308 SkRect bounds = SkRect::MakeXYWH(x, y,
2309 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002310 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002311 SkRect tmp = bounds;
2312 if (paint) {
2313 paint->computeFastBounds(tmp, &tmp);
2314 }
2315 if (this->quickReject(tmp)) {
2316 return;
2317 }
reeda85d4d02015-05-06 12:56:48 -07002318 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002319 // At this point we need a real paint object. If the caller passed null, then we should
2320 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2321 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2322 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002323
reeda2217ef2016-07-20 06:04:34 -07002324 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002325 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2326 *paint);
2327 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002328 special = this->getDevice()->makeSpecial(image);
2329 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002330 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002331 }
2332 }
2333
reed262a71b2015-12-05 13:07:27 -08002334 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2335
reeda85d4d02015-05-06 12:56:48 -07002336 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002337 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002338 if (special) {
2339 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002340 iter.fDevice->ctm().mapXY(x, y, &pt);
2341 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002342 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002343 SkScalarRoundToInt(pt.fY), pnt,
2344 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002345 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002346 iter.fDevice->drawImageRect(
2347 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2348 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002349 }
reeda85d4d02015-05-06 12:56:48 -07002350 }
halcanary9d524f22016-03-29 09:03:52 -07002351
reeda85d4d02015-05-06 12:56:48 -07002352 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002353}
2354
reed41af9662015-01-05 07:49:08 -08002355void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002356 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002357 SkPaint realPaint;
2358 paint = init_image_paint(&realPaint, paint);
2359
halcanary96fcdcc2015-08-27 07:41:13 -07002360 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002361 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002362 if (paint) {
2363 paint->computeFastBounds(dst, &storage);
2364 }
2365 if (this->quickReject(storage)) {
2366 return;
2367 }
reeda85d4d02015-05-06 12:56:48 -07002368 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002369 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002370
Ben Wagner2c312c42018-06-27 14:46:46 -04002371 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002372
reeda85d4d02015-05-06 12:56:48 -07002373 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002374 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002375 }
halcanary9d524f22016-03-29 09:03:52 -07002376
reeda85d4d02015-05-06 12:56:48 -07002377 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002378}
2379
reed41af9662015-01-05 07:49:08 -08002380void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002381 SkDEBUGCODE(bitmap.validate();)
2382
reed33366972015-10-08 09:22:02 -07002383 if (bitmap.drawsNothing()) {
2384 return;
2385 }
2386
Mike Reedf441cfc2018-04-11 14:50:16 -04002387 SkPaint realPaint;
2388 init_image_paint(&realPaint, paint);
2389 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002390
Mike Reed822128b2017-02-28 16:41:03 -05002391 SkRect bounds;
2392 bitmap.getBounds(&bounds);
2393 bounds.offset(x, y);
2394 bool canFastBounds = paint->canComputeFastBounds();
2395 if (canFastBounds) {
2396 SkRect storage;
2397 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002398 return;
2399 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002400 }
reed@google.com4b226022011-01-11 18:32:13 +00002401
reeda2217ef2016-07-20 06:04:34 -07002402 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002403 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2404 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002405 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002406 special = this->getDevice()->makeSpecial(bitmap);
2407 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002408 drawAsSprite = false;
2409 }
2410 }
2411
Mike Reed822128b2017-02-28 16:41:03 -05002412 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002413
2414 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002415 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002416 if (special) {
reed262a71b2015-12-05 13:07:27 -08002417 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002418 iter.fDevice->ctm().mapXY(x, y, &pt);
2419 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002420 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002421 SkScalarRoundToInt(pt.fY), pnt,
2422 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002423 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002424 SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2425 iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2426 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002427 }
reed33366972015-10-08 09:22:02 -07002428 }
msarettfbfa2582016-08-12 08:29:08 -07002429
reed33366972015-10-08 09:22:02 -07002430 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002431}
2432
reed@google.com9987ec32011-09-07 11:57:52 +00002433// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002434void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002435 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002436 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002437 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002438 return;
2439 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +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 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002446 }
reed@google.com3d608122011-11-21 15:16:16 +00002447
reed@google.com33535f32012-09-25 15:37:50 +00002448 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002449 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002450 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002451 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002452
Ben Wagner2c312c42018-06-27 14:46:46 -04002453 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002454
reed@google.com33535f32012-09-25 15:37:50 +00002455 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002456 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002457 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002458
reed@google.com33535f32012-09-25 15:37:50 +00002459 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002460}
2461
reed41af9662015-01-05 07:49:08 -08002462void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002463 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002464 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002465 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002466}
2467
reed4c21dc52015-06-25 12:32:03 -07002468void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2469 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002470 SkPaint realPaint;
2471 paint = init_image_paint(&realPaint, paint);
2472
halcanary96fcdcc2015-08-27 07:41:13 -07002473 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002474 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002475 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2476 return;
2477 }
reed@google.com3d608122011-11-21 15:16:16 +00002478 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002479 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002480
Ben Wagner2c312c42018-06-27 14:46:46 -04002481 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002482
reed4c21dc52015-06-25 12:32:03 -07002483 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002484 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002485 }
halcanary9d524f22016-03-29 09:03:52 -07002486
reed4c21dc52015-06-25 12:32:03 -07002487 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002488}
2489
reed41af9662015-01-05 07:49:08 -08002490void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2491 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002492 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002493 SkPaint realPaint;
2494 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002495
halcanary96fcdcc2015-08-27 07:41:13 -07002496 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002497 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002498 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2499 return;
2500 }
reed4c21dc52015-06-25 12:32:03 -07002501 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002502 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002503
Ben Wagner2c312c42018-06-27 14:46:46 -04002504 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002505
reed4c21dc52015-06-25 12:32:03 -07002506 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002507 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002508 }
halcanary9d524f22016-03-29 09:03:52 -07002509
reed4c21dc52015-06-25 12:32:03 -07002510 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002511}
2512
msarett16882062016-08-16 09:31:08 -07002513void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2514 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002515 SkPaint realPaint;
2516 paint = init_image_paint(&realPaint, paint);
2517
msarett16882062016-08-16 09:31:08 -07002518 if (nullptr == paint || paint->canComputeFastBounds()) {
2519 SkRect storage;
2520 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2521 return;
2522 }
2523 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002524 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002525
Ben Wagner2c312c42018-06-27 14:46:46 -04002526 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002527
2528 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002529 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002530 }
2531
2532 LOOPER_END
2533}
2534
2535void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2536 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002537 SkPaint realPaint;
2538 paint = init_image_paint(&realPaint, paint);
2539
msarett16882062016-08-16 09:31:08 -07002540 if (nullptr == paint || paint->canComputeFastBounds()) {
2541 SkRect storage;
2542 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2543 return;
2544 }
2545 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002546 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002547
Ben Wagner2c312c42018-06-27 14:46:46 -04002548 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002549
2550 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002551 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002552 }
2553
2554 LOOPER_END
2555}
2556
fmalita00d5c2c2014-08-21 08:53:26 -07002557void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2558 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002559 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002560 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002561 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002562 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002563 SkRect tmp;
2564 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2565 return;
2566 }
2567 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002568 }
2569
fmalita024f9962015-03-03 19:08:17 -08002570 // We cannot filter in the looper as we normally do, because the paint is
2571 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002572 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002573
fmalitaaa1b9122014-08-28 14:32:24 -07002574 while (iter.next()) {
Mike Reed30cf62b2018-12-20 11:18:24 -05002575 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002576 }
2577
fmalitaaa1b9122014-08-28 14:32:24 -07002578 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002579}
2580
Mike Reed358fcad2018-11-23 15:27:51 -05002581// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002582void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002583 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2584 TRACE_EVENT0("skia", TRACE_FUNC);
2585 if (byteLength) {
2586 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002587 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002588 }
2589}
Mike Reed4f81bb72019-01-23 09:23:00 -05002590
fmalita00d5c2c2014-08-21 08:53:26 -07002591void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2592 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002593 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002594 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002595 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002596 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002597}
reed@google.come0d9ce82014-04-23 04:00:17 +00002598
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002599void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002600 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002601 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002602
2603 while (iter.next()) {
2604 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002605 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002606 }
2607
2608 LOOPER_END
2609}
2610
dandovb3c9d1c2014-08-12 08:34:29 -07002611void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002612 const SkPoint texCoords[4], SkBlendMode bmode,
2613 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002614 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002615 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002616 return;
2617 }
mtklein6cfa73a2014-08-13 13:33:49 -07002618
Mike Reedfaba3712016-11-03 14:45:31 -04002619 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002620}
2621
2622void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002623 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002624 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002625 // Since a patch is always within the convex hull of the control points, we discard it when its
2626 // bounding rectangle is completely outside the current clip.
2627 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002628 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002629 if (this->quickReject(bounds)) {
2630 return;
2631 }
mtklein6cfa73a2014-08-13 13:33:49 -07002632
Ben Wagner2c312c42018-06-27 14:46:46 -04002633 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002634
dandovecfff212014-08-04 10:02:00 -07002635 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002636 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002637 }
mtklein6cfa73a2014-08-13 13:33:49 -07002638
dandovecfff212014-08-04 10:02:00 -07002639 LOOPER_END
2640}
2641
reeda8db7282015-07-07 10:22:31 -07002642void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002643#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002644 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002645#endif
reede3b38ce2016-01-08 09:18:44 -08002646 RETURN_ON_NULL(dr);
2647 if (x || y) {
2648 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2649 this->onDrawDrawable(dr, &matrix);
2650 } else {
2651 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002652 }
2653}
2654
reeda8db7282015-07-07 10:22:31 -07002655void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002656#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002657 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002658#endif
reede3b38ce2016-01-08 09:18:44 -08002659 RETURN_ON_NULL(dr);
2660 if (matrix && matrix->isIdentity()) {
2661 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002662 }
reede3b38ce2016-01-08 09:18:44 -08002663 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002664}
2665
2666void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002667 // drawable bounds are no longer reliable (e.g. android displaylist)
2668 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002669 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002670}
2671
reed71c3c762015-06-24 10:29:17 -07002672void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002673 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002674 const SkRect* cull, const SkPaint* paint) {
2675 if (cull && this->quickReject(*cull)) {
2676 return;
2677 }
2678
2679 SkPaint pnt;
2680 if (paint) {
2681 pnt = *paint;
2682 }
halcanary9d524f22016-03-29 09:03:52 -07002683
Ben Wagner2c312c42018-06-27 14:46:46 -04002684 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002685 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002686 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002687 }
2688 LOOPER_END
2689}
2690
reedf70b5312016-03-04 16:36:20 -08002691void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2692 SkASSERT(key);
2693
2694 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002695 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002696 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002697 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002698 }
2699 LOOPER_END
2700}
2701
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002702void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2703 SkColor color, SkBlendMode mode) {
2704 SkASSERT(r.isSorted());
2705
2706 // If this used a paint, it would be a filled color with blend mode, which does not
2707 // need to use an autodraw loop, so use SkDrawIter directly.
2708 if (this->quickReject(r)) {
2709 return;
2710 }
2711
2712 this->predrawNotify();
2713 SkDrawIter iter(this);
2714 while(iter.next()) {
2715 iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2716 }
2717}
2718
2719void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2720 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2721 const SkPaint* paint, SrcRectConstraint constraint) {
2722 SkPaint realPaint;
2723 init_image_paint(&realPaint, paint);
2724
2725 // Looper is used when there are image filters, which drawEdgeAAImageSet needs to support
2726 // for Chromium's RenderPassDrawQuads' filters.
2727 LOOPER_BEGIN(realPaint, nullptr)
2728 while (iter.next()) {
2729 iter.fDevice->drawEdgeAAImageSet(
2730 imageSet, count, dstClips, preViewMatrices, looper.paint(), constraint);
2731 }
2732 LOOPER_END
2733}
2734
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735//////////////////////////////////////////////////////////////////////////////
2736// These methods are NOT virtual, and therefore must call back into virtual
2737// methods, rather than actually drawing themselves.
2738//////////////////////////////////////////////////////////////////////////////
2739
reed374772b2016-10-05 17:33:02 -07002740void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002741 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002742 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002743 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002744 this->drawPaint(paint);
2745}
2746
2747void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002748 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002749 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2750}
2751
Mike Reed3661bc92017-02-22 13:21:42 -05002752void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002754 pts[0].set(x0, y0);
2755 pts[1].set(x1, y1);
2756 this->drawPoints(kLines_PointMode, 2, pts, paint);
2757}
2758
Mike Reed3661bc92017-02-22 13:21:42 -05002759void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002760 if (radius < 0) {
2761 radius = 0;
2762 }
2763
2764 SkRect r;
2765 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002766 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002767}
2768
2769void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2770 const SkPaint& paint) {
2771 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002772 SkRRect rrect;
2773 rrect.setRectXY(r, rx, ry);
2774 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002775 } else {
2776 this->drawRect(r, paint);
2777 }
2778}
2779
reed@android.com8a1c16f2008-12-17 15:59:43 +00002780void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2781 SkScalar sweepAngle, bool useCenter,
2782 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002783 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002784 if (oval.isEmpty() || !sweepAngle) {
2785 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786 }
bsalomon21af9ca2016-08-25 12:29:23 -07002787 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002788}
2789
reed@android.comf76bacf2009-05-13 14:00:33 +00002790///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002791#ifdef SK_DISABLE_SKPICTURE
2792void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002793
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002794
2795void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2796 const SkPaint* paint) {}
2797#else
Mike Klein88d90712018-01-27 17:30:04 +00002798/**
2799 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2800 * against the playback cost of recursing into the subpicture to get at its actual ops.
2801 *
2802 * For now we pick a conservatively small value, though measurement (and other heuristics like
2803 * the type of ops contained) may justify changing this value.
2804 */
2805#define kMaxPictureOpsToUnrollInsteadOfRef 1
2806
reedd5fa1a42014-08-09 11:08:05 -07002807void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002808 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002809 RETURN_ON_NULL(picture);
2810
reede3b38ce2016-01-08 09:18:44 -08002811 if (matrix && matrix->isIdentity()) {
2812 matrix = nullptr;
2813 }
Mike Klein88d90712018-01-27 17:30:04 +00002814 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2815 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2816 picture->playback(this);
2817 } else {
2818 this->onDrawPicture(picture, matrix, paint);
2819 }
reedd5fa1a42014-08-09 11:08:05 -07002820}
robertphillips9b14f262014-06-04 05:40:44 -07002821
reedd5fa1a42014-08-09 11:08:05 -07002822void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2823 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002824 if (!paint || paint->canComputeFastBounds()) {
2825 SkRect bounds = picture->cullRect();
2826 if (paint) {
2827 paint->computeFastBounds(bounds, &bounds);
2828 }
2829 if (matrix) {
2830 matrix->mapRect(&bounds);
2831 }
2832 if (this->quickReject(bounds)) {
2833 return;
2834 }
2835 }
2836
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002837 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002838 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002839}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002840#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002841
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842///////////////////////////////////////////////////////////////////////////////
2843///////////////////////////////////////////////////////////////////////////////
2844
reed3aafe112016-08-18 12:45:34 -07002845SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002846 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847
2848 SkASSERT(canvas);
2849
reed3aafe112016-08-18 12:45:34 -07002850 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002851 fDone = !fImpl->next();
2852}
2853
2854SkCanvas::LayerIter::~LayerIter() {
2855 fImpl->~SkDrawIter();
2856}
2857
2858void SkCanvas::LayerIter::next() {
2859 fDone = !fImpl->next();
2860}
2861
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002862SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002863 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002864}
2865
2866const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002867 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002868}
2869
2870const SkPaint& SkCanvas::LayerIter::paint() const {
2871 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002872 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002873 paint = &fDefaultPaint;
2874 }
2875 return *paint;
2876}
2877
Mike Reedca37f322018-03-08 13:22:16 -05002878SkIRect SkCanvas::LayerIter::clipBounds() const {
2879 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002880}
2881
reed@android.com8a1c16f2008-12-17 15:59:43 +00002882int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2883int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002884
2885///////////////////////////////////////////////////////////////////////////////
2886
Brian Osmane8a98632019-04-10 10:26:10 -04002887SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2888SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2889SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2890SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2891
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002892SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2893 const SkRect& dstRect, int matrixIndex, float alpha,
2894 unsigned aaFlags, bool hasClip)
2895 : fImage(std::move(image))
2896 , fSrcRect(srcRect)
2897 , fDstRect(dstRect)
2898 , fMatrixIndex(matrixIndex)
2899 , fAlpha(alpha)
2900 , fAAFlags(aaFlags)
2901 , fHasClip(hasClip) {}
2902
2903SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2904 const SkRect& dstRect, float alpha, unsigned aaFlags)
2905 : fImage(std::move(image))
2906 , fSrcRect(srcRect)
2907 , fDstRect(dstRect)
2908 , fAlpha(alpha)
2909 , fAAFlags(aaFlags) {}
2910
2911///////////////////////////////////////////////////////////////////////////////
2912
Mike Reed5df49342016-11-12 08:06:55 -06002913std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002914 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002915 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002916 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002917 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002918
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002919 SkBitmap bitmap;
2920 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002921 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002922 }
Mike Reed12f77342017-11-08 11:19:52 -05002923
2924 return props ?
2925 skstd::make_unique<SkCanvas>(bitmap, *props) :
2926 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002927}
reedd5fa1a42014-08-09 11:08:05 -07002928
2929///////////////////////////////////////////////////////////////////////////////
2930
Florin Malitaee424ac2016-12-01 12:47:59 -05002931SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002932 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002933
Florin Malita439ace92016-12-02 12:05:41 -05002934SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002935 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002936
Herb Derbyefe39bc2018-05-01 17:06:20 -04002937SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002938 : INHERITED(device) {}
2939
Florin Malitaee424ac2016-12-01 12:47:59 -05002940SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2941 (void)this->INHERITED::getSaveLayerStrategy(rec);
2942 return kNoLayer_SaveLayerStrategy;
2943}
2944
Mike Reed148b7fd2018-12-18 17:38:18 -05002945bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2946 return false;
2947}
2948
Florin Malitaee424ac2016-12-01 12:47:59 -05002949///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002950
reed73603f32016-09-20 08:42:38 -07002951static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2952static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2953static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2954static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2955static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2956static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002957
2958///////////////////////////////////////////////////////////////////////////////////////////////////
2959
2960SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2961 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002962 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002963 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2964 SkIPoint origin = dev->getOrigin();
2965 SkMatrix ctm = this->getTotalMatrix();
2966 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2967
2968 SkIRect clip = fMCRec->fRasterClip.getBounds();
2969 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002970 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002971 clip.setEmpty();
2972 }
2973
2974 fAllocator->updateHandle(handle, ctm, clip);
2975 return handle;
2976 }
2977 return nullptr;
2978}
2979
2980static bool install(SkBitmap* bm, const SkImageInfo& info,
2981 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002982 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002983}
2984
2985SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2986 SkBitmap* bm) {
2987 SkRasterHandleAllocator::Rec rec;
2988 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2989 return nullptr;
2990 }
2991 return rec.fHandle;
2992}
2993
2994std::unique_ptr<SkCanvas>
2995SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2996 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04002997 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05002998 return nullptr;
2999 }
3000
3001 SkBitmap bm;
3002 Handle hndl;
3003
3004 if (rec) {
3005 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3006 } else {
3007 hndl = alloc->allocBitmap(info, &bm);
3008 }
3009 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3010}
Mike Reed7c9c9e42018-01-03 09:23:34 -05003011
3012///////////////////////////////////////////////////////////////////////////////////////////////////
3013
3014