blob: a0c956b5ef4ba5518096006209b4c0a511280507 [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);
1144 if (localBounds) {
1145 this->drawRect(*localBounds, paint);
1146 } else {
1147 this->drawPaint(paint);
1148 }
1149}
1150
reed@android.com8a1c16f2008-12-17 15:59:43 +00001151void SkCanvas::internalRestore() {
1152 SkASSERT(fMCStack.count() != 0);
1153
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001154 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001155 DeviceCM* layer = fMCRec->fLayer; // may be null
1156 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001157 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001158
Mike Reed148b7fd2018-12-18 17:38:18 -05001159 // move this out before we do the actual restore
1160 auto backImage = std::move(fMCRec->fBackImage);
1161
reed@android.com8a1c16f2008-12-17 15:59:43 +00001162 // now do the normal restore()
1163 fMCRec->~MCRec(); // balanced in save()
1164 fMCStack.pop_back();
1165 fMCRec = (MCRec*)fMCStack.back();
1166
Mike Reedc42a1cd2017-02-14 14:25:14 -05001167 if (fMCRec) {
1168 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1169 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001170
Mike Reed148b7fd2018-12-18 17:38:18 -05001171 if (backImage) {
1172 SkPaint paint;
1173 paint.setBlendMode(SkBlendMode::kDstOver);
1174 const int x = backImage->fLoc.x();
1175 const int y = backImage->fLoc.y();
1176 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1177 nullptr, SkMatrix::I());
1178 }
1179
reed@android.com8a1c16f2008-12-17 15:59:43 +00001180 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1181 since if we're being recorded, we don't want to record this (the
1182 recorder will have already recorded the restore).
1183 */
bsalomon49f085d2014-09-05 13:34:00 -07001184 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001185 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001186 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001187 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001188 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001189 layer->fPaint.get(),
1190 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001191 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001192 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001193 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001194 delete layer;
reedb679ca82015-04-07 04:40:48 -07001195 } else {
1196 // we're at the root
reeda499f902015-05-01 09:34:31 -07001197 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001198 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001199 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001201 }
msarettfbfa2582016-08-12 08:29:08 -07001202
1203 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001204 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001205 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1206 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001207}
1208
reede8f30622016-03-23 18:59:25 -07001209sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001210 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001211 props = &fProps;
1212 }
1213 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001214}
1215
reede8f30622016-03-23 18:59:25 -07001216sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001217 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001218 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001219}
1220
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001221SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001222 return this->onImageInfo();
1223}
1224
1225SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001226 SkBaseDevice* dev = this->getDevice();
1227 if (dev) {
1228 return dev->imageInfo();
1229 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001230 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001231 }
1232}
1233
brianosman898235c2016-04-06 07:38:23 -07001234bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001235 return this->onGetProps(props);
1236}
1237
1238bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001239 SkBaseDevice* dev = this->getDevice();
1240 if (dev) {
1241 if (props) {
1242 *props = fProps;
1243 }
1244 return true;
1245 } else {
1246 return false;
1247 }
1248}
1249
reed6ceeebd2016-03-09 14:26:26 -08001250bool SkCanvas::peekPixels(SkPixmap* pmap) {
1251 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001252}
1253
reed884e97c2015-05-26 11:31:54 -07001254bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001255 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001256 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001257}
1258
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001259void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001260 SkPixmap pmap;
1261 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001262 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001263 }
1264 if (info) {
1265 *info = pmap.info();
1266 }
1267 if (rowBytes) {
1268 *rowBytes = pmap.rowBytes();
1269 }
1270 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001271 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001272 }
reed884e97c2015-05-26 11:31:54 -07001273 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001274}
1275
reed884e97c2015-05-26 11:31:54 -07001276bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001277 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001278 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001279}
1280
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282
Mike Reed8bcd1282019-03-13 16:51:54 -04001283// In our current design/features, we should never have a layer (src) in a different colorspace
1284// than its parent (dst), so we assert that here. This is called out from other asserts, in case
1285// we add some feature in the future to allow a given layer/imagefilter to operate in a specific
1286// colorspace.
1287static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) {
1288 SkASSERT(src == dst);
1289}
1290
Florin Malita53f77bd2017-04-28 13:48:37 -04001291void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1292 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001294 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 paint = &tmp;
1296 }
reed@google.com4b226022011-01-11 18:32:13 +00001297
Ben Wagner2c312c42018-06-27 14:46:46 -04001298 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001299
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001301 SkBaseDevice* dstDev = iter.fDevice;
Mike Reed8bcd1282019-03-13 16:51:54 -04001302 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1303 srcDev->imageInfo().colorSpace());
reed@google.com76dd2772012-01-05 21:15:07 +00001304 paint = &looper.paint();
1305 SkImageFilter* filter = paint->getImageFilter();
1306 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001307 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001308 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1309 if (specialImage) {
Mike Reed8bcd1282019-03-13 16:51:54 -04001310 check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(),
1311 specialImage->getColorSpace());
Florin Malita53f77bd2017-04-28 13:48:37 -04001312 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1313 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001314 }
reed@google.com76dd2772012-01-05 21:15:07 +00001315 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001316 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001317 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318 }
reeda2217ef2016-07-20 06:04:34 -07001319
reed@google.com4e2b3d32011-04-07 14:18:59 +00001320 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321}
1322
reed32704672015-12-16 08:27:10 -08001323/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001324
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001325void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001326 if (dx || dy) {
1327 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001328 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001329
reedfe69b502016-09-12 06:31:48 -07001330 // Translate shouldn't affect the is-scale-translateness of the matrix.
1331 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001332
Mike Reedc42a1cd2017-02-14 14:25:14 -05001333 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001334
reedfe69b502016-09-12 06:31:48 -07001335 this->didTranslate(dx,dy);
1336 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337}
1338
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001339void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001340 SkMatrix m;
1341 m.setScale(sx, sy);
1342 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343}
1344
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001345void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001346 SkMatrix m;
1347 m.setRotate(degrees);
1348 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001349}
1350
bungeman7438bfc2016-07-12 15:01:19 -07001351void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1352 SkMatrix m;
1353 m.setRotate(degrees, px, py);
1354 this->concat(m);
1355}
1356
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001357void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001358 SkMatrix m;
1359 m.setSkew(sx, sy);
1360 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001361}
1362
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001363void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001364 if (matrix.isIdentity()) {
1365 return;
1366 }
1367
reed2ff1fce2014-12-11 07:07:37 -08001368 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001369 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001370 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001371
Mike Reed7627fa52017-02-08 10:07:53 -05001372 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001373
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001374 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001375}
1376
reed8c30a812016-04-20 16:36:51 -07001377void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001378 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001379 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001380
Mike Reedc42a1cd2017-02-14 14:25:14 -05001381 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001382}
1383
1384void SkCanvas::setMatrix(const SkMatrix& matrix) {
1385 this->checkForDeferredSave();
1386 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001387 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001388}
1389
reed@android.com8a1c16f2008-12-17 15:59:43 +00001390void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001391 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001392}
1393
1394//////////////////////////////////////////////////////////////////////////////
1395
Mike Reedc1f77742016-12-09 09:00:50 -05001396void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001397 if (!rect.isFinite()) {
1398 return;
1399 }
reed2ff1fce2014-12-11 07:07:37 -08001400 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001401 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1402 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001403}
1404
Mike Reedc1f77742016-12-09 09:00:50 -05001405void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001406 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001407
Mike Reed7627fa52017-02-08 10:07:53 -05001408 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001409
reedc64eff52015-11-21 12:39:45 -08001410 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001411 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1412 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001413 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414}
1415
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001416void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1417 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001418 if (fClipRestrictionRect.isEmpty()) {
1419 // we notify the device, but we *dont* resolve deferred saves (since we're just
1420 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001421 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001422 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001423 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001424 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001425 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001426 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001427 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1428 }
1429}
1430
Mike Reedc1f77742016-12-09 09:00:50 -05001431void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001432 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001433 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001434 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001435 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1436 } else {
1437 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001438 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001439}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001440
Mike Reedc1f77742016-12-09 09:00:50 -05001441void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001442 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001443
Brian Salomona3b45d42016-10-03 11:36:16 -04001444 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001445
Mike Reed7627fa52017-02-08 10:07:53 -05001446 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001447
Mike Reed20800c82017-11-15 16:09:04 -05001448 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1449 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001450 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001451}
1452
Mike Reedc1f77742016-12-09 09:00:50 -05001453void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001454 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001455 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001456
1457 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1458 SkRect r;
1459 if (path.isRect(&r)) {
1460 this->onClipRect(r, op, edgeStyle);
1461 return;
1462 }
1463 SkRRect rrect;
1464 if (path.isOval(&r)) {
1465 rrect.setOval(r);
1466 this->onClipRRect(rrect, op, edgeStyle);
1467 return;
1468 }
1469 if (path.isRRect(&rrect)) {
1470 this->onClipRRect(rrect, op, edgeStyle);
1471 return;
1472 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001473 }
robertphillips39f05382015-11-24 09:30:12 -08001474
1475 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001476}
1477
Mike Reedc1f77742016-12-09 09:00:50 -05001478void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001479 AutoValidateClip avc(this);
1480
Brian Salomona3b45d42016-10-03 11:36:16 -04001481 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001482
Mike Reed7627fa52017-02-08 10:07:53 -05001483 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001484
Brian Salomona3b45d42016-10-03 11:36:16 -04001485 const SkPath* rasterClipPath = &path;
1486 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001487 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1488 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001489 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001490}
1491
Mike Reedc1f77742016-12-09 09:00:50 -05001492void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001493 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001494 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001495}
1496
Mike Reedc1f77742016-12-09 09:00:50 -05001497void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001498 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001499
reed@google.com5c3d1472011-02-22 19:12:23 +00001500 AutoValidateClip avc(this);
1501
Mike Reed20800c82017-11-15 16:09:04 -05001502 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001503 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001504}
1505
reed@google.com819c9212011-02-23 18:56:55 +00001506#ifdef SK_DEBUG
1507void SkCanvas::validateClip() const {
1508 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001509 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001510 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001511 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001512 return;
1513 }
reed@google.com819c9212011-02-23 18:56:55 +00001514}
1515#endif
1516
Mike Reeda1361362017-03-07 09:37:29 -05001517bool SkCanvas::androidFramework_isClipAA() const {
1518 bool containsAA = false;
1519
1520 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1521
1522 return containsAA;
1523}
1524
1525class RgnAccumulator {
1526 SkRegion* fRgn;
1527public:
1528 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1529 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1530 SkIPoint origin = device->getOrigin();
1531 if (origin.x() | origin.y()) {
1532 rgn->translate(origin.x(), origin.y());
1533 }
1534 fRgn->op(*rgn, SkRegion::kUnion_Op);
1535 }
1536};
1537
1538void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1539 RgnAccumulator accum(rgn);
1540 SkRegion tmp;
1541
1542 rgn->setEmpty();
1543 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001544}
1545
reed@google.com5c3d1472011-02-22 19:12:23 +00001546///////////////////////////////////////////////////////////////////////////////
1547
reed@google.com754de5f2014-02-24 19:38:20 +00001548bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001549 return fMCRec->fRasterClip.isEmpty();
1550
1551 // TODO: should we only use the conservative answer in a recording canvas?
1552#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001553 SkBaseDevice* dev = this->getTopDevice();
1554 // if no device we return true
1555 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001556#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001557}
1558
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001559bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001560 SkBaseDevice* dev = this->getTopDevice();
1561 // if no device we return false
1562 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001563}
1564
msarettfbfa2582016-08-12 08:29:08 -07001565static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1566#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1567 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1568 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1569 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1570 return 0xF != _mm_movemask_ps(mask);
1571#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1572 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1573 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1574 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1575 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1576#else
1577 SkRect devRectAsRect;
1578 SkRect devClipAsRect;
1579 devRect.store(&devRectAsRect.fLeft);
1580 devClip.store(&devClipAsRect.fLeft);
1581 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1582#endif
1583}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001584
msarettfbfa2582016-08-12 08:29:08 -07001585// It's important for this function to not be inlined. Otherwise the compiler will share code
1586// between the fast path and the slow path, resulting in two slow paths.
1587static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1588 const SkMatrix& matrix) {
1589 SkRect deviceRect;
1590 matrix.mapRect(&deviceRect, src);
1591 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1592}
1593
1594bool SkCanvas::quickReject(const SkRect& src) const {
1595#ifdef SK_DEBUG
1596 // Verify that fDeviceClipBounds are set properly.
1597 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001598 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001599 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001600 } else {
msarettfbfa2582016-08-12 08:29:08 -07001601 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001602 }
msarettfbfa2582016-08-12 08:29:08 -07001603
msarett9637ea92016-08-18 14:03:30 -07001604 // Verify that fIsScaleTranslate is set properly.
1605 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001606#endif
1607
msarett9637ea92016-08-18 14:03:30 -07001608 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001609 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1610 }
1611
1612 // We inline the implementation of mapScaleTranslate() for the fast path.
1613 float sx = fMCRec->fMatrix.getScaleX();
1614 float sy = fMCRec->fMatrix.getScaleY();
1615 float tx = fMCRec->fMatrix.getTranslateX();
1616 float ty = fMCRec->fMatrix.getTranslateY();
1617 Sk4f scale(sx, sy, sx, sy);
1618 Sk4f trans(tx, ty, tx, ty);
1619
1620 // Apply matrix.
1621 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1622
1623 // Make sure left < right, top < bottom.
1624 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1625 Sk4f min = Sk4f::Min(ltrb, rblt);
1626 Sk4f max = Sk4f::Max(ltrb, rblt);
1627 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1628 // ARM this sequence generates the fastest (a single instruction).
1629 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1630
1631 // Check if the device rect is NaN or outside the clip.
1632 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001633}
1634
reed@google.com3b3e8952012-08-16 20:53:31 +00001635bool SkCanvas::quickReject(const SkPath& path) const {
1636 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001637}
1638
Mike Klein83c8dd92017-11-28 17:08:45 -05001639SkRect SkCanvas::getLocalClipBounds() const {
1640 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001641 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001642 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001643 }
1644
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001645 SkMatrix inverse;
1646 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001647 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001648 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001649 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001650
Mike Reed42e8c532017-01-23 14:09:13 -05001651 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001652 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001653 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001654
Mike Reedb57b9312018-04-23 12:12:54 -04001655 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001656 inverse.mapRect(&bounds, r);
1657 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001658}
1659
Mike Klein83c8dd92017-11-28 17:08:45 -05001660SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001661 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001662}
1663
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001665 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001666}
1667
Brian Osman11052242016-10-27 14:47:55 -04001668GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001669 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001670 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001671}
1672
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001673GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001674 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001675 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001676}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001677
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001678void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1679 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001680 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001681 if (outer.isEmpty()) {
1682 return;
1683 }
1684 if (inner.isEmpty()) {
1685 this->drawRRect(outer, paint);
1686 return;
1687 }
1688
1689 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001690 // be able to return ...
1691 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001692 //
1693 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001694 if (!outer.getBounds().contains(inner.getBounds())) {
1695 return;
1696 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001697
1698 this->onDrawDRRect(outer, inner, paint);
1699}
1700
reed41af9662015-01-05 07:49:08 -08001701void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001702 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001703 this->onDrawPaint(paint);
1704}
1705
1706void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001707 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001708 // To avoid redundant logic in our culling code and various backends, we always sort rects
1709 // before passing them along.
1710 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001711}
1712
Mike Reedd5674082019-04-19 15:00:47 -04001713void SkCanvas::drawClippedToSaveBehind(const SkPaint& paint) {
1714 TRACE_EVENT0("skia", TRACE_FUNC);
1715 this->onDrawBehind(paint);
1716}
1717
msarettdca352e2016-08-26 06:37:45 -07001718void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001719 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001720 if (region.isEmpty()) {
1721 return;
1722 }
1723
1724 if (region.isRect()) {
1725 return this->drawIRect(region.getBounds(), paint);
1726 }
1727
1728 this->onDrawRegion(region, paint);
1729}
1730
reed41af9662015-01-05 07:49:08 -08001731void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001732 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001733 // To avoid redundant logic in our culling code and various backends, we always sort rects
1734 // before passing them along.
1735 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001736}
1737
1738void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001739 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001740 this->onDrawRRect(rrect, paint);
1741}
1742
1743void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001744 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001745 this->onDrawPoints(mode, count, pts, paint);
1746}
1747
Mike Reede88a1cb2017-03-17 09:50:46 -04001748void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1749 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001750 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001751 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001752 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1753 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001754 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001755}
1756
1757void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001758 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001759 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001760 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1761}
1762
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001763void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1764 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001765 TRACE_EVENT0("skia", TRACE_FUNC);
1766 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001767 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001768 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1769}
1770
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001771void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1772 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001773 TRACE_EVENT0("skia", TRACE_FUNC);
1774 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001775 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001776 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001777}
1778
1779void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001780 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001781 this->onDrawPath(path, paint);
1782}
1783
reeda85d4d02015-05-06 12:56:48 -07001784void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001785 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001786 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001787 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001788}
1789
Mike Reedc4e31092018-01-30 11:15:27 -05001790// Returns true if the rect can be "filled" : non-empty and finite
1791static bool fillable(const SkRect& r) {
1792 SkScalar w = r.width();
1793 SkScalar h = r.height();
1794 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1795}
1796
reede47829b2015-08-06 10:02:53 -07001797void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1798 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001799 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001800 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001801 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001802 return;
1803 }
1804 this->onDrawImageRect(image, &src, dst, paint, constraint);
1805}
reed41af9662015-01-05 07:49:08 -08001806
reed84984ef2015-07-17 07:09:43 -07001807void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1808 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001809 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001810 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001811}
1812
Brian Salomonf08002c2018-10-26 16:15:46 -04001813void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001814 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001815 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001816 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001817}
reede47829b2015-08-06 10:02:53 -07001818
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001819namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001820class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001821public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001822 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1823 if (!origPaint) {
1824 return;
1825 }
1826 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1827 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1828 }
1829 if (origPaint->getMaskFilter()) {
1830 fPaint.writable()->setMaskFilter(nullptr);
1831 }
1832 if (origPaint->isAntiAlias()) {
1833 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001834 }
1835 }
1836
1837 const SkPaint* get() const {
1838 return fPaint;
1839 }
1840
1841private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001842 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001843};
1844} // namespace
1845
reed4c21dc52015-06-25 12:32:03 -07001846void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1847 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001848 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001849 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001850 if (dst.isEmpty()) {
1851 return;
1852 }
msarett552bca92016-08-03 06:53:26 -07001853 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001854 LatticePaint latticePaint(paint);
1855 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001856 } else {
reede47829b2015-08-06 10:02:53 -07001857 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001858 }
reed4c21dc52015-06-25 12:32:03 -07001859}
1860
msarett16882062016-08-16 09:31:08 -07001861void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1862 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001863 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001864 RETURN_ON_NULL(image);
1865 if (dst.isEmpty()) {
1866 return;
1867 }
msarett71df2d72016-09-30 12:41:42 -07001868
1869 SkIRect bounds;
1870 Lattice latticePlusBounds = lattice;
1871 if (!latticePlusBounds.fBounds) {
1872 bounds = SkIRect::MakeWH(image->width(), image->height());
1873 latticePlusBounds.fBounds = &bounds;
1874 }
1875
1876 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001877 LatticePaint latticePaint(paint);
1878 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001879 } else {
1880 this->drawImageRect(image, dst, paint);
1881 }
1882}
1883
reed41af9662015-01-05 07:49:08 -08001884void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001885 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001886 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001887 return;
1888 }
reed41af9662015-01-05 07:49:08 -08001889 this->onDrawBitmap(bitmap, dx, dy, paint);
1890}
1891
reede47829b2015-08-06 10:02:53 -07001892void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001893 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001894 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001895 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001896 return;
1897 }
reede47829b2015-08-06 10:02:53 -07001898 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001899}
1900
reed84984ef2015-07-17 07:09:43 -07001901void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1902 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001903 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001904}
1905
reede47829b2015-08-06 10:02:53 -07001906void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1907 SrcRectConstraint constraint) {
1908 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1909 constraint);
1910}
reede47829b2015-08-06 10:02:53 -07001911
reed41af9662015-01-05 07:49:08 -08001912void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1913 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001914 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001915 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001916 return;
1917 }
msarett552bca92016-08-03 06:53:26 -07001918 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001919 LatticePaint latticePaint(paint);
1920 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001921 } else {
reeda5517e22015-07-14 10:54:12 -07001922 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001923 }
reed41af9662015-01-05 07:49:08 -08001924}
1925
msarettc573a402016-08-02 08:05:56 -07001926void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1927 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001928 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001929 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001930 return;
1931 }
msarett71df2d72016-09-30 12:41:42 -07001932
1933 SkIRect bounds;
1934 Lattice latticePlusBounds = lattice;
1935 if (!latticePlusBounds.fBounds) {
1936 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1937 latticePlusBounds.fBounds = &bounds;
1938 }
1939
1940 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001941 LatticePaint latticePaint(paint);
1942 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001943 } else {
msarett16882062016-08-16 09:31:08 -07001944 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001945 }
msarettc573a402016-08-02 08:05:56 -07001946}
1947
reed71c3c762015-06-24 10:29:17 -07001948void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001949 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001950 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001951 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001952 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001953 if (count <= 0) {
1954 return;
1955 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001956 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001957 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001958 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001959}
1960
reedf70b5312016-03-04 16:36:20 -08001961void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001962 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001963 if (key) {
1964 this->onDrawAnnotation(rect, key, value);
1965 }
1966}
1967
reede47829b2015-08-06 10:02:53 -07001968void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1969 const SkPaint* paint, SrcRectConstraint constraint) {
1970 if (src) {
1971 this->drawImageRect(image, *src, dst, paint, constraint);
1972 } else {
1973 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1974 dst, paint, constraint);
1975 }
1976}
1977void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1978 const SkPaint* paint, SrcRectConstraint constraint) {
1979 if (src) {
1980 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1981 } else {
1982 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1983 dst, paint, constraint);
1984 }
1985}
1986
Mike Reed4204da22017-05-17 08:53:36 -04001987void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001988 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001989 this->onDrawShadowRec(path, rec);
1990}
1991
1992void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1993 SkPaint paint;
1994 const SkRect& pathBounds = path.getBounds();
1995
Ben Wagner2c312c42018-06-27 14:46:46 -04001996 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001997 while (iter.next()) {
1998 iter.fDevice->drawShadow(path, rec);
1999 }
2000 LOOPER_END
2001}
2002
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002003void SkCanvas::experimental_DrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
2004 QuadAAFlags aaFlags, SkColor color, SkBlendMode mode) {
2005 TRACE_EVENT0("skia", TRACE_FUNC);
2006 // Make sure the rect is sorted before passing it along
2007 this->onDrawEdgeAAQuad(rect.makeSorted(), clip, aaFlags, color, mode);
2008}
2009
2010void SkCanvas::experimental_DrawEdgeAAImageSet(const ImageSetEntry imageSet[], int cnt,
2011 const SkPoint dstClips[],
2012 const SkMatrix preViewMatrices[],
2013 const SkPaint* paint,
2014 SrcRectConstraint constraint) {
2015 TRACE_EVENT0("skia", TRACE_FUNC);
2016 this->onDrawEdgeAAImageSet(imageSet, cnt, dstClips, preViewMatrices, paint, constraint);
2017}
2018
reed@android.com8a1c16f2008-12-17 15:59:43 +00002019//////////////////////////////////////////////////////////////////////////////
2020// These are the virtual drawing methods
2021//////////////////////////////////////////////////////////////////////////////
2022
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002023void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002024 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002025 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2026 }
2027}
2028
reed41af9662015-01-05 07:49:08 -08002029void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002030 this->internalDrawPaint(paint);
2031}
2032
2033void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002034 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002035
2036 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002037 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002038 }
2039
reed@google.com4e2b3d32011-04-07 14:18:59 +00002040 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002041}
2042
reed41af9662015-01-05 07:49:08 -08002043void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2044 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002045 if ((long)count <= 0) {
2046 return;
2047 }
2048
Mike Reed822128b2017-02-28 16:41:03 -05002049 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002050 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002051 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002052 // special-case 2 points (common for drawing a single line)
2053 if (2 == count) {
2054 r.set(pts[0], pts[1]);
2055 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002056 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002057 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002058 if (!r.isFinite()) {
2059 return;
2060 }
Mike Reed822128b2017-02-28 16:41:03 -05002061 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002062 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2063 return;
2064 }
2065 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002066 }
reed@google.coma584aed2012-05-16 14:06:02 +00002067
halcanary96fcdcc2015-08-27 07:41:13 -07002068 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002069
Ben Wagner2c312c42018-06-27 14:46:46 -04002070 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002071
reed@android.com8a1c16f2008-12-17 15:59:43 +00002072 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002073 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002074 }
reed@google.com4b226022011-01-11 18:32:13 +00002075
reed@google.com4e2b3d32011-04-07 14:18:59 +00002076 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002077}
2078
reed4a167172016-08-18 17:15:25 -07002079static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2080 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07002081 (intptr_t)paint.getLooper() ) != 0;
2082}
2083
reed41af9662015-01-05 07:49:08 -08002084void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002085 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002086 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002087 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002088 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002089 return;
2090 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002091 }
reed@google.com4b226022011-01-11 18:32:13 +00002092
reed4a167172016-08-18 17:15:25 -07002093 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002094 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002095
reed4a167172016-08-18 17:15:25 -07002096 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002097 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002098 }
2099
2100 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002101 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002102 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002103 SkDrawIter iter(this);
2104 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002105 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002106 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002107 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002108}
2109
msarett44df6512016-08-25 13:54:30 -07002110void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002111 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002112 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002113 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002114 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2115 return;
2116 }
msarett44df6512016-08-25 13:54:30 -07002117 }
2118
Ben Wagner2c312c42018-06-27 14:46:46 -04002119 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002120
2121 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002122 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002123 }
2124
2125 LOOPER_END
2126}
2127
Mike Reedd5674082019-04-19 15:00:47 -04002128void SkCanvas::onDrawBehind(const SkPaint& paint) {
2129 SkIRect bounds;
2130 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kBack_IterStart);
2131 for (;;) {
2132 const MCRec* rec = (const MCRec*)iter.prev();
2133 if (!rec) {
2134 return; // no backimages, so nothing to draw
2135 }
2136 if (rec->fBackImage) {
2137 bounds = SkIRect::MakeXYWH(rec->fBackImage->fLoc.fX, rec->fBackImage->fLoc.fY,
2138 rec->fBackImage->fImage->width(),
2139 rec->fBackImage->fImage->height());
2140 break;
2141 }
2142 }
2143
2144 LOOPER_BEGIN(paint, nullptr)
2145
2146 while (iter.next()) {
2147 SkBaseDevice* dev = iter.fDevice;
2148
2149 SkMatrix ctm = dev->ctm();
2150 dev->save();
2151 // We use clipRegion because it is already defined to operate in dev-space
2152 // (i.e. ignores the ctm). However, it is going to first translate by -origin,
2153 // but we don't want that, so we undo that before calling in.
2154 SkRegion rgn(bounds.makeOffset(dev->fOrigin.fX, dev->fOrigin.fY));
2155 dev->clipRegion(rgn, SkClipOp::kIntersect);
2156 dev->drawPaint(looper.paint());
2157 dev->restore(ctm);
2158 }
2159
2160 LOOPER_END
2161}
2162
reed41af9662015-01-05 07:49:08 -08002163void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002164 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002165 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002166 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002167 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002168 return;
2169 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002170 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002171
Ben Wagner2c312c42018-06-27 14:46:46 -04002172 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002173
2174 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002175 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002176 }
2177
2178 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002179}
2180
bsalomonac3aa242016-08-19 11:25:19 -07002181void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2182 SkScalar sweepAngle, bool useCenter,
2183 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002184 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002185 if (paint.canComputeFastBounds()) {
2186 SkRect storage;
2187 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002188 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002189 return;
2190 }
bsalomonac3aa242016-08-19 11:25:19 -07002191 }
2192
Ben Wagner2c312c42018-06-27 14:46:46 -04002193 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002194
2195 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002196 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002197 }
2198
2199 LOOPER_END
2200}
2201
reed41af9662015-01-05 07:49:08 -08002202void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002203 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002204 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002205 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2206 return;
2207 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002208 }
2209
2210 if (rrect.isRect()) {
2211 // call the non-virtual version
2212 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002213 return;
2214 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002215 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002216 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2217 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002218 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002219
Ben Wagner2c312c42018-06-27 14:46:46 -04002220 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002221
2222 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002223 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002224 }
2225
2226 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002227}
2228
Mike Reed822128b2017-02-28 16:41:03 -05002229void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002230 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002231 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002232 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2233 return;
2234 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002235 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002236
Ben Wagner2c312c42018-06-27 14:46:46 -04002237 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002238
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002239 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002240 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002241 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002242
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002243 LOOPER_END
2244}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002245
reed41af9662015-01-05 07:49:08 -08002246void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002247 if (!path.isFinite()) {
2248 return;
2249 }
2250
Mike Reed822128b2017-02-28 16:41:03 -05002251 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002252 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002253 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002254 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2255 return;
2256 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002257 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002258
Mike Reed822128b2017-02-28 16:41:03 -05002259 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002260 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002261 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002262 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002263 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002264 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002265
Ben Wagner2c312c42018-06-27 14:46:46 -04002266 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002267
2268 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002269 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002270 }
2271
reed@google.com4e2b3d32011-04-07 14:18:59 +00002272 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002273}
2274
reed262a71b2015-12-05 13:07:27 -08002275bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002276 if (!paint.getImageFilter()) {
2277 return false;
2278 }
2279
2280 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002281 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002282 return false;
2283 }
2284
2285 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2286 // Once we can filter and the filter will return a result larger than itself, we should be
2287 // able to remove this constraint.
2288 // skbug.com/4526
2289 //
2290 SkPoint pt;
2291 ctm.mapXY(x, y, &pt);
2292 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2293 return ir.contains(fMCRec->fRasterClip.getBounds());
2294}
2295
Mike Reedf441cfc2018-04-11 14:50:16 -04002296// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2297// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2298// null.
2299static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2300 if (paintParam) {
2301 *real = *paintParam;
2302 real->setStyle(SkPaint::kFill_Style);
2303 real->setPathEffect(nullptr);
2304 paintParam = real;
2305 }
2306 return paintParam;
2307}
2308
reeda85d4d02015-05-06 12:56:48 -07002309void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002310 SkPaint realPaint;
2311 paint = init_image_paint(&realPaint, paint);
2312
reeda85d4d02015-05-06 12:56:48 -07002313 SkRect bounds = SkRect::MakeXYWH(x, y,
2314 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002315 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002316 SkRect tmp = bounds;
2317 if (paint) {
2318 paint->computeFastBounds(tmp, &tmp);
2319 }
2320 if (this->quickReject(tmp)) {
2321 return;
2322 }
reeda85d4d02015-05-06 12:56:48 -07002323 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002324 // At this point we need a real paint object. If the caller passed null, then we should
2325 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2326 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2327 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002328
reeda2217ef2016-07-20 06:04:34 -07002329 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002330 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2331 *paint);
2332 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002333 special = this->getDevice()->makeSpecial(image);
2334 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002335 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002336 }
2337 }
2338
reed262a71b2015-12-05 13:07:27 -08002339 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2340
reeda85d4d02015-05-06 12:56:48 -07002341 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002342 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002343 if (special) {
2344 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002345 iter.fDevice->ctm().mapXY(x, y, &pt);
2346 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002347 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002348 SkScalarRoundToInt(pt.fY), pnt,
2349 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002350 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002351 iter.fDevice->drawImageRect(
2352 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2353 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002354 }
reeda85d4d02015-05-06 12:56:48 -07002355 }
halcanary9d524f22016-03-29 09:03:52 -07002356
reeda85d4d02015-05-06 12:56:48 -07002357 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002358}
2359
reed41af9662015-01-05 07:49:08 -08002360void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002361 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002362 SkPaint realPaint;
2363 paint = init_image_paint(&realPaint, paint);
2364
halcanary96fcdcc2015-08-27 07:41:13 -07002365 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002366 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002367 if (paint) {
2368 paint->computeFastBounds(dst, &storage);
2369 }
2370 if (this->quickReject(storage)) {
2371 return;
2372 }
reeda85d4d02015-05-06 12:56:48 -07002373 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002374 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002375
Ben Wagner2c312c42018-06-27 14:46:46 -04002376 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002377
reeda85d4d02015-05-06 12:56:48 -07002378 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002379 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002380 }
halcanary9d524f22016-03-29 09:03:52 -07002381
reeda85d4d02015-05-06 12:56:48 -07002382 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002383}
2384
reed41af9662015-01-05 07:49:08 -08002385void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002386 SkDEBUGCODE(bitmap.validate();)
2387
reed33366972015-10-08 09:22:02 -07002388 if (bitmap.drawsNothing()) {
2389 return;
2390 }
2391
Mike Reedf441cfc2018-04-11 14:50:16 -04002392 SkPaint realPaint;
2393 init_image_paint(&realPaint, paint);
2394 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002395
Mike Reed822128b2017-02-28 16:41:03 -05002396 SkRect bounds;
2397 bitmap.getBounds(&bounds);
2398 bounds.offset(x, y);
2399 bool canFastBounds = paint->canComputeFastBounds();
2400 if (canFastBounds) {
2401 SkRect storage;
2402 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002403 return;
2404 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002405 }
reed@google.com4b226022011-01-11 18:32:13 +00002406
reeda2217ef2016-07-20 06:04:34 -07002407 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002408 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2409 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002410 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002411 special = this->getDevice()->makeSpecial(bitmap);
2412 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002413 drawAsSprite = false;
2414 }
2415 }
2416
Mike Reed822128b2017-02-28 16:41:03 -05002417 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002418
2419 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002420 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002421 if (special) {
reed262a71b2015-12-05 13:07:27 -08002422 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002423 iter.fDevice->ctm().mapXY(x, y, &pt);
2424 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002425 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002426 SkScalarRoundToInt(pt.fY), pnt,
2427 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002428 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002429 SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2430 iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2431 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002432 }
reed33366972015-10-08 09:22:02 -07002433 }
msarettfbfa2582016-08-12 08:29:08 -07002434
reed33366972015-10-08 09:22:02 -07002435 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002436}
2437
reed@google.com9987ec32011-09-07 11:57:52 +00002438// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002439void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002440 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002441 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002442 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002443 return;
2444 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002445
halcanary96fcdcc2015-08-27 07:41:13 -07002446 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002447 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002448 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2449 return;
2450 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002451 }
reed@google.com3d608122011-11-21 15:16:16 +00002452
reed@google.com33535f32012-09-25 15:37:50 +00002453 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002454 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002455 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002456 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002457
Ben Wagner2c312c42018-06-27 14:46:46 -04002458 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002459
reed@google.com33535f32012-09-25 15:37:50 +00002460 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002461 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002462 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002463
reed@google.com33535f32012-09-25 15:37:50 +00002464 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002465}
2466
reed41af9662015-01-05 07:49:08 -08002467void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002468 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002469 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002470 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002471}
2472
reed4c21dc52015-06-25 12:32:03 -07002473void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2474 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002475 SkPaint realPaint;
2476 paint = init_image_paint(&realPaint, paint);
2477
halcanary96fcdcc2015-08-27 07:41:13 -07002478 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002479 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002480 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2481 return;
2482 }
reed@google.com3d608122011-11-21 15:16:16 +00002483 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002484 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002485
Ben Wagner2c312c42018-06-27 14:46:46 -04002486 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002487
reed4c21dc52015-06-25 12:32:03 -07002488 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002489 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002490 }
halcanary9d524f22016-03-29 09:03:52 -07002491
reed4c21dc52015-06-25 12:32:03 -07002492 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002493}
2494
reed41af9662015-01-05 07:49:08 -08002495void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2496 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002497 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002498 SkPaint realPaint;
2499 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002500
halcanary96fcdcc2015-08-27 07:41:13 -07002501 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002502 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002503 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2504 return;
2505 }
reed4c21dc52015-06-25 12:32:03 -07002506 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002507 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002508
Ben Wagner2c312c42018-06-27 14:46:46 -04002509 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002510
reed4c21dc52015-06-25 12:32:03 -07002511 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002512 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002513 }
halcanary9d524f22016-03-29 09:03:52 -07002514
reed4c21dc52015-06-25 12:32:03 -07002515 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002516}
2517
msarett16882062016-08-16 09:31:08 -07002518void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2519 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002520 SkPaint realPaint;
2521 paint = init_image_paint(&realPaint, paint);
2522
msarett16882062016-08-16 09:31:08 -07002523 if (nullptr == paint || paint->canComputeFastBounds()) {
2524 SkRect storage;
2525 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2526 return;
2527 }
2528 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002529 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002530
Ben Wagner2c312c42018-06-27 14:46:46 -04002531 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002532
2533 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002534 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002535 }
2536
2537 LOOPER_END
2538}
2539
2540void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2541 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002542 SkPaint realPaint;
2543 paint = init_image_paint(&realPaint, paint);
2544
msarett16882062016-08-16 09:31:08 -07002545 if (nullptr == paint || paint->canComputeFastBounds()) {
2546 SkRect storage;
2547 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2548 return;
2549 }
2550 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002551 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002552
Ben Wagner2c312c42018-06-27 14:46:46 -04002553 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002554
2555 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002556 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002557 }
2558
2559 LOOPER_END
2560}
2561
fmalita00d5c2c2014-08-21 08:53:26 -07002562void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2563 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002564 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002565 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002566 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002567 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002568 SkRect tmp;
2569 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2570 return;
2571 }
2572 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002573 }
2574
fmalita024f9962015-03-03 19:08:17 -08002575 // We cannot filter in the looper as we normally do, because the paint is
2576 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002577 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002578
fmalitaaa1b9122014-08-28 14:32:24 -07002579 while (iter.next()) {
Mike Reed30cf62b2018-12-20 11:18:24 -05002580 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002581 }
2582
fmalitaaa1b9122014-08-28 14:32:24 -07002583 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002584}
2585
Mike Reed358fcad2018-11-23 15:27:51 -05002586// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002587void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002588 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2589 TRACE_EVENT0("skia", TRACE_FUNC);
2590 if (byteLength) {
2591 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002592 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002593 }
2594}
Mike Reed4f81bb72019-01-23 09:23:00 -05002595
fmalita00d5c2c2014-08-21 08:53:26 -07002596void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2597 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002598 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002599 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002600 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002601 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002602}
reed@google.come0d9ce82014-04-23 04:00:17 +00002603
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002604void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002605 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002606 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002607
2608 while (iter.next()) {
2609 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002610 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002611 }
2612
2613 LOOPER_END
2614}
2615
dandovb3c9d1c2014-08-12 08:34:29 -07002616void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002617 const SkPoint texCoords[4], SkBlendMode bmode,
2618 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002619 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002620 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002621 return;
2622 }
mtklein6cfa73a2014-08-13 13:33:49 -07002623
Mike Reedfaba3712016-11-03 14:45:31 -04002624 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002625}
2626
2627void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002628 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002629 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002630 // Since a patch is always within the convex hull of the control points, we discard it when its
2631 // bounding rectangle is completely outside the current clip.
2632 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002633 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002634 if (this->quickReject(bounds)) {
2635 return;
2636 }
mtklein6cfa73a2014-08-13 13:33:49 -07002637
Ben Wagner2c312c42018-06-27 14:46:46 -04002638 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002639
dandovecfff212014-08-04 10:02:00 -07002640 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002641 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002642 }
mtklein6cfa73a2014-08-13 13:33:49 -07002643
dandovecfff212014-08-04 10:02:00 -07002644 LOOPER_END
2645}
2646
reeda8db7282015-07-07 10:22:31 -07002647void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002648#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002649 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002650#endif
reede3b38ce2016-01-08 09:18:44 -08002651 RETURN_ON_NULL(dr);
2652 if (x || y) {
2653 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2654 this->onDrawDrawable(dr, &matrix);
2655 } else {
2656 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002657 }
2658}
2659
reeda8db7282015-07-07 10:22:31 -07002660void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002661#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002662 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002663#endif
reede3b38ce2016-01-08 09:18:44 -08002664 RETURN_ON_NULL(dr);
2665 if (matrix && matrix->isIdentity()) {
2666 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002667 }
reede3b38ce2016-01-08 09:18:44 -08002668 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002669}
2670
2671void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002672 // drawable bounds are no longer reliable (e.g. android displaylist)
2673 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002674 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002675}
2676
reed71c3c762015-06-24 10:29:17 -07002677void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002678 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002679 const SkRect* cull, const SkPaint* paint) {
2680 if (cull && this->quickReject(*cull)) {
2681 return;
2682 }
2683
2684 SkPaint pnt;
2685 if (paint) {
2686 pnt = *paint;
2687 }
halcanary9d524f22016-03-29 09:03:52 -07002688
Ben Wagner2c312c42018-06-27 14:46:46 -04002689 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002690 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002691 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002692 }
2693 LOOPER_END
2694}
2695
reedf70b5312016-03-04 16:36:20 -08002696void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2697 SkASSERT(key);
2698
2699 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002700 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002701 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002702 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002703 }
2704 LOOPER_END
2705}
2706
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002707void SkCanvas::onDrawEdgeAAQuad(const SkRect& r, const SkPoint clip[4], QuadAAFlags edgeAA,
2708 SkColor color, SkBlendMode mode) {
2709 SkASSERT(r.isSorted());
2710
2711 // If this used a paint, it would be a filled color with blend mode, which does not
2712 // need to use an autodraw loop, so use SkDrawIter directly.
2713 if (this->quickReject(r)) {
2714 return;
2715 }
2716
2717 this->predrawNotify();
2718 SkDrawIter iter(this);
2719 while(iter.next()) {
2720 iter.fDevice->drawEdgeAAQuad(r, clip, edgeAA, color, mode);
2721 }
2722}
2723
2724void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count,
2725 const SkPoint dstClips[], const SkMatrix preViewMatrices[],
2726 const SkPaint* paint, SrcRectConstraint constraint) {
2727 SkPaint realPaint;
2728 init_image_paint(&realPaint, paint);
2729
2730 // Looper is used when there are image filters, which drawEdgeAAImageSet needs to support
2731 // for Chromium's RenderPassDrawQuads' filters.
2732 LOOPER_BEGIN(realPaint, nullptr)
2733 while (iter.next()) {
2734 iter.fDevice->drawEdgeAAImageSet(
2735 imageSet, count, dstClips, preViewMatrices, looper.paint(), constraint);
2736 }
2737 LOOPER_END
2738}
2739
reed@android.com8a1c16f2008-12-17 15:59:43 +00002740//////////////////////////////////////////////////////////////////////////////
2741// These methods are NOT virtual, and therefore must call back into virtual
2742// methods, rather than actually drawing themselves.
2743//////////////////////////////////////////////////////////////////////////////
2744
reed374772b2016-10-05 17:33:02 -07002745void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002746 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002747 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002748 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002749 this->drawPaint(paint);
2750}
2751
2752void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002753 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002754 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2755}
2756
Mike Reed3661bc92017-02-22 13:21:42 -05002757void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002758 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002759 pts[0].set(x0, y0);
2760 pts[1].set(x1, y1);
2761 this->drawPoints(kLines_PointMode, 2, pts, paint);
2762}
2763
Mike Reed3661bc92017-02-22 13:21:42 -05002764void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002765 if (radius < 0) {
2766 radius = 0;
2767 }
2768
2769 SkRect r;
2770 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002771 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772}
2773
2774void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2775 const SkPaint& paint) {
2776 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002777 SkRRect rrect;
2778 rrect.setRectXY(r, rx, ry);
2779 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002780 } else {
2781 this->drawRect(r, paint);
2782 }
2783}
2784
reed@android.com8a1c16f2008-12-17 15:59:43 +00002785void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2786 SkScalar sweepAngle, bool useCenter,
2787 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002788 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002789 if (oval.isEmpty() || !sweepAngle) {
2790 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791 }
bsalomon21af9ca2016-08-25 12:29:23 -07002792 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002793}
2794
reed@android.comf76bacf2009-05-13 14:00:33 +00002795///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002796#ifdef SK_DISABLE_SKPICTURE
2797void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002798
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002799
2800void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2801 const SkPaint* paint) {}
2802#else
Mike Klein88d90712018-01-27 17:30:04 +00002803/**
2804 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2805 * against the playback cost of recursing into the subpicture to get at its actual ops.
2806 *
2807 * For now we pick a conservatively small value, though measurement (and other heuristics like
2808 * the type of ops contained) may justify changing this value.
2809 */
2810#define kMaxPictureOpsToUnrollInsteadOfRef 1
2811
reedd5fa1a42014-08-09 11:08:05 -07002812void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002813 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002814 RETURN_ON_NULL(picture);
2815
reede3b38ce2016-01-08 09:18:44 -08002816 if (matrix && matrix->isIdentity()) {
2817 matrix = nullptr;
2818 }
Mike Klein88d90712018-01-27 17:30:04 +00002819 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2820 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2821 picture->playback(this);
2822 } else {
2823 this->onDrawPicture(picture, matrix, paint);
2824 }
reedd5fa1a42014-08-09 11:08:05 -07002825}
robertphillips9b14f262014-06-04 05:40:44 -07002826
reedd5fa1a42014-08-09 11:08:05 -07002827void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2828 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002829 if (!paint || paint->canComputeFastBounds()) {
2830 SkRect bounds = picture->cullRect();
2831 if (paint) {
2832 paint->computeFastBounds(bounds, &bounds);
2833 }
2834 if (matrix) {
2835 matrix->mapRect(&bounds);
2836 }
2837 if (this->quickReject(bounds)) {
2838 return;
2839 }
2840 }
2841
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002842 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002843 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002844}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002845#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002846
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847///////////////////////////////////////////////////////////////////////////////
2848///////////////////////////////////////////////////////////////////////////////
2849
reed3aafe112016-08-18 12:45:34 -07002850SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002851 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002852
2853 SkASSERT(canvas);
2854
reed3aafe112016-08-18 12:45:34 -07002855 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002856 fDone = !fImpl->next();
2857}
2858
2859SkCanvas::LayerIter::~LayerIter() {
2860 fImpl->~SkDrawIter();
2861}
2862
2863void SkCanvas::LayerIter::next() {
2864 fDone = !fImpl->next();
2865}
2866
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002867SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002868 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002869}
2870
2871const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002872 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002873}
2874
2875const SkPaint& SkCanvas::LayerIter::paint() const {
2876 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002877 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002878 paint = &fDefaultPaint;
2879 }
2880 return *paint;
2881}
2882
Mike Reedca37f322018-03-08 13:22:16 -05002883SkIRect SkCanvas::LayerIter::clipBounds() const {
2884 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002885}
2886
reed@android.com8a1c16f2008-12-17 15:59:43 +00002887int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2888int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002889
2890///////////////////////////////////////////////////////////////////////////////
2891
Brian Osmane8a98632019-04-10 10:26:10 -04002892SkCanvas::ImageSetEntry::ImageSetEntry() = default;
2893SkCanvas::ImageSetEntry::~ImageSetEntry() = default;
2894SkCanvas::ImageSetEntry::ImageSetEntry(const ImageSetEntry&) = default;
2895SkCanvas::ImageSetEntry& SkCanvas::ImageSetEntry::operator=(const ImageSetEntry&) = default;
2896
Michael Ludwig390f0cc2019-03-19 09:16:38 -04002897SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2898 const SkRect& dstRect, int matrixIndex, float alpha,
2899 unsigned aaFlags, bool hasClip)
2900 : fImage(std::move(image))
2901 , fSrcRect(srcRect)
2902 , fDstRect(dstRect)
2903 , fMatrixIndex(matrixIndex)
2904 , fAlpha(alpha)
2905 , fAAFlags(aaFlags)
2906 , fHasClip(hasClip) {}
2907
2908SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
2909 const SkRect& dstRect, float alpha, unsigned aaFlags)
2910 : fImage(std::move(image))
2911 , fSrcRect(srcRect)
2912 , fDstRect(dstRect)
2913 , fAlpha(alpha)
2914 , fAAFlags(aaFlags) {}
2915
2916///////////////////////////////////////////////////////////////////////////////
2917
Mike Reed5df49342016-11-12 08:06:55 -06002918std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002919 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002920 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002921 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002922 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002923
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002924 SkBitmap bitmap;
2925 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002926 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002927 }
Mike Reed12f77342017-11-08 11:19:52 -05002928
2929 return props ?
2930 skstd::make_unique<SkCanvas>(bitmap, *props) :
2931 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002932}
reedd5fa1a42014-08-09 11:08:05 -07002933
2934///////////////////////////////////////////////////////////////////////////////
2935
Florin Malitaee424ac2016-12-01 12:47:59 -05002936SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002937 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002938
Florin Malita439ace92016-12-02 12:05:41 -05002939SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002940 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002941
Herb Derbyefe39bc2018-05-01 17:06:20 -04002942SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002943 : INHERITED(device) {}
2944
Florin Malitaee424ac2016-12-01 12:47:59 -05002945SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2946 (void)this->INHERITED::getSaveLayerStrategy(rec);
2947 return kNoLayer_SaveLayerStrategy;
2948}
2949
Mike Reed148b7fd2018-12-18 17:38:18 -05002950bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2951 return false;
2952}
2953
Florin Malitaee424ac2016-12-01 12:47:59 -05002954///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002955
reed73603f32016-09-20 08:42:38 -07002956static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2957static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2958static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2959static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2960static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2961static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002962
2963///////////////////////////////////////////////////////////////////////////////////////////////////
2964
2965SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2966 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002967 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002968 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2969 SkIPoint origin = dev->getOrigin();
2970 SkMatrix ctm = this->getTotalMatrix();
2971 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2972
2973 SkIRect clip = fMCRec->fRasterClip.getBounds();
2974 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002975 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002976 clip.setEmpty();
2977 }
2978
2979 fAllocator->updateHandle(handle, ctm, clip);
2980 return handle;
2981 }
2982 return nullptr;
2983}
2984
2985static bool install(SkBitmap* bm, const SkImageInfo& info,
2986 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002987 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002988}
2989
2990SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2991 SkBitmap* bm) {
2992 SkRasterHandleAllocator::Rec rec;
2993 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2994 return nullptr;
2995 }
2996 return rec.fHandle;
2997}
2998
2999std::unique_ptr<SkCanvas>
3000SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3001 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04003002 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05003003 return nullptr;
3004 }
3005
3006 SkBitmap bm;
3007 Handle hndl;
3008
3009 if (rec) {
3010 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3011 } else {
3012 hndl = alloc->allocBitmap(info, &bm);
3013 }
3014 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3015}
Mike Reed7c9c9e42018-01-03 09:23:34 -05003016
3017///////////////////////////////////////////////////////////////////////////////////////////////////
3018
3019