blob: 225b9e5a4ee6c01422ab22fffc81d9c290f3eb48 [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 Kleine083f7c2018-02-07 12:54:27 -0500954static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500955 // Need to force L32 for now if we have an image filter.
956 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
957 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500958 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800959 }
Mike Klein649fb732018-02-26 15:09:16 -0500960
961 SkColorType ct = prev.colorType();
962 if (prev.bytesPerPixel() <= 4) {
963 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
964 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
965 ct = kN32_SkColorType;
966 }
967 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800968}
969
reed4960eee2015-12-18 07:09:18 -0800970void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700971 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800972 const SkRect* bounds = rec.fBounds;
973 const SkPaint* paint = rec.fPaint;
974 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
975
reed8c30a812016-04-20 16:36:51 -0700976 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400977 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700978 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400979 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700980 SkMatrix remainder;
981 SkSize scale;
982 /*
983 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
984 * but they do handle scaling. To accommodate this, we do the following:
985 *
986 * 1. Stash off the current CTM
987 * 2. Decompose the CTM into SCALE and REMAINDER
988 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
989 * contains the REMAINDER
990 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
991 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
992 * of the original imagefilter, and draw that (via drawSprite)
993 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
994 *
995 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
996 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
997 */
reed96a04f32016-04-25 09:25:15 -0700998 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -0700999 stashedMatrix.decomposeScale(&scale, &remainder))
1000 {
1001 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001002 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001003 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1004 SkPaint* p = lazyP.set(*paint);
1005 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1006 SkFilterQuality::kLow_SkFilterQuality,
1007 sk_ref_sp(imageFilter)));
1008 imageFilter = p->getImageFilter();
1009 paint = p;
1010 }
reed8c30a812016-04-20 16:36:51 -07001011
junov@chromium.orga907ac32012-02-24 21:54:07 +00001012 // do this before we create the layer. We don't call the public save() since
1013 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001014 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001015
junov@chromium.orga907ac32012-02-24 21:54:07 +00001016 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001017 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001018 if (modifiedRec) {
1019 // In this case there will be no layer in which to stash the matrix so we need to
1020 // revert the prior MCRec to its earlier state.
1021 modifiedRec->fMatrix = stashedMatrix;
1022 }
reed2ff1fce2014-12-11 07:07:37 -08001023 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001024 }
1025
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001026 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1027 // the clipRectBounds() call above?
1028 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001029 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001030 }
1031
reed8dc0ccb2015-03-20 06:32:52 -07001032 SkPixelGeometry geo = fProps.pixelGeometry();
1033 if (paint) {
reed76033be2015-03-14 10:54:31 -07001034 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001035 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001036 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001037 }
1038 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001039
robertphillips5139e502016-07-19 05:10:40 -07001040 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001041 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001042 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001043 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001044 }
reedb2db8982014-11-13 12:41:02 -08001045
Mike Kleine083f7c2018-02-07 12:54:27 -05001046 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001047
Hal Canary704cd322016-11-07 14:13:52 -05001048 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001049 {
Florin Malita07e4adf2019-01-07 16:34:18 -05001050 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType();
reeddaa57bf2015-05-15 10:39:17 -07001051 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001052 const bool trackCoverage =
1053 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001054 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001055 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001056 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001057 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001058 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1059 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001060 return;
reed61f501f2015-04-29 08:34:00 -07001061 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001062 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001063 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064
Mike Reedb43a3e02017-02-11 10:18:58 -05001065 // only have a "next" if this new layer doesn't affect the clip (rare)
1066 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067 fMCRec->fLayer = layer;
1068 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001069
Mike Reedc61abee2017-02-28 17:45:27 -05001070 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001071 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001072 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001073 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001074
Mike Reedc42a1cd2017-02-14 14:25:14 -05001075 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1076
1077 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1078 if (layer->fNext) {
1079 // need to punch a hole in the previous device, so we don't draw there, given that
1080 // the new top-layer will allow drawing to happen "below" it.
1081 SkRegion hole(ir);
1082 do {
1083 layer = layer->fNext;
1084 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1085 } while (layer->fNext);
1086 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087}
1088
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001089int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001090 if (0xFF == alpha) {
1091 return this->saveLayer(bounds, nullptr);
1092 } else {
1093 SkPaint tmpPaint;
1094 tmpPaint.setAlpha(alpha);
1095 return this->saveLayer(bounds, &tmpPaint);
1096 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001097}
1098
Mike Reed148b7fd2018-12-18 17:38:18 -05001099void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1100 SkIRect devBounds;
1101 if (localBounds) {
1102 SkRect tmp;
1103 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1104 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1105 devBounds.setEmpty();
1106 }
1107 } else {
1108 devBounds = this->getDeviceClipBounds();
1109 }
1110 if (devBounds.isEmpty()) {
1111 return;
1112 }
1113
1114 SkBaseDevice* device = this->getTopDevice();
1115 if (nullptr == device) { // Do we still need this check???
1116 return;
1117 }
1118
1119 // need the bounds relative to the device itself
1120 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1121
1122 auto backImage = device->snapBackImage(devBounds);
1123 if (!backImage) {
1124 return;
1125 }
1126
1127 // we really need the save, so we can wack the fMCRec
1128 this->checkForDeferredSave();
1129
1130 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1131
1132 SkPaint paint;
1133 paint.setBlendMode(SkBlendMode::kClear);
1134 if (localBounds) {
1135 this->drawRect(*localBounds, paint);
1136 } else {
1137 this->drawPaint(paint);
1138 }
1139}
1140
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141void SkCanvas::internalRestore() {
1142 SkASSERT(fMCStack.count() != 0);
1143
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001144 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145 DeviceCM* layer = fMCRec->fLayer; // may be null
1146 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001147 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001148
Mike Reed148b7fd2018-12-18 17:38:18 -05001149 // move this out before we do the actual restore
1150 auto backImage = std::move(fMCRec->fBackImage);
1151
reed@android.com8a1c16f2008-12-17 15:59:43 +00001152 // now do the normal restore()
1153 fMCRec->~MCRec(); // balanced in save()
1154 fMCStack.pop_back();
1155 fMCRec = (MCRec*)fMCStack.back();
1156
Mike Reedc42a1cd2017-02-14 14:25:14 -05001157 if (fMCRec) {
1158 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1159 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001160
Mike Reed148b7fd2018-12-18 17:38:18 -05001161 if (backImage) {
1162 SkPaint paint;
1163 paint.setBlendMode(SkBlendMode::kDstOver);
1164 const int x = backImage->fLoc.x();
1165 const int y = backImage->fLoc.y();
1166 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1167 nullptr, SkMatrix::I());
1168 }
1169
reed@android.com8a1c16f2008-12-17 15:59:43 +00001170 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1171 since if we're being recorded, we don't want to record this (the
1172 recorder will have already recorded the restore).
1173 */
bsalomon49f085d2014-09-05 13:34:00 -07001174 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001175 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001176 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001177 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001178 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001179 layer->fPaint.get(),
1180 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001181 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001182 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001183 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001184 delete layer;
reedb679ca82015-04-07 04:40:48 -07001185 } else {
1186 // we're at the root
reeda499f902015-05-01 09:34:31 -07001187 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001188 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001189 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001190 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001191 }
msarettfbfa2582016-08-12 08:29:08 -07001192
1193 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001194 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001195 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1196 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001197}
1198
reede8f30622016-03-23 18:59:25 -07001199sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001200 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001201 props = &fProps;
1202 }
1203 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001204}
1205
reede8f30622016-03-23 18:59:25 -07001206sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001207 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001208 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001209}
1210
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001211SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001212 return this->onImageInfo();
1213}
1214
1215SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001216 SkBaseDevice* dev = this->getDevice();
1217 if (dev) {
1218 return dev->imageInfo();
1219 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001220 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001221 }
1222}
1223
brianosman898235c2016-04-06 07:38:23 -07001224bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001225 return this->onGetProps(props);
1226}
1227
1228bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001229 SkBaseDevice* dev = this->getDevice();
1230 if (dev) {
1231 if (props) {
1232 *props = fProps;
1233 }
1234 return true;
1235 } else {
1236 return false;
1237 }
1238}
1239
reed6ceeebd2016-03-09 14:26:26 -08001240bool SkCanvas::peekPixels(SkPixmap* pmap) {
1241 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001242}
1243
reed884e97c2015-05-26 11:31:54 -07001244bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001245 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001246 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001247}
1248
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001249void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001250 SkPixmap pmap;
1251 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001252 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001253 }
1254 if (info) {
1255 *info = pmap.info();
1256 }
1257 if (rowBytes) {
1258 *rowBytes = pmap.rowBytes();
1259 }
1260 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001261 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001262 }
reed884e97c2015-05-26 11:31:54 -07001263 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001264}
1265
reed884e97c2015-05-26 11:31:54 -07001266bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001267 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001268 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001269}
1270
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272
Florin Malita53f77bd2017-04-28 13:48:37 -04001273void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1274 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001276 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277 paint = &tmp;
1278 }
reed@google.com4b226022011-01-11 18:32:13 +00001279
Ben Wagner2c312c42018-06-27 14:46:46 -04001280 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001281
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001283 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001284 paint = &looper.paint();
1285 SkImageFilter* filter = paint->getImageFilter();
1286 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001287 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001288 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1289 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001290 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1291 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001292 }
reed@google.com76dd2772012-01-05 21:15:07 +00001293 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001294 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001295 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296 }
reeda2217ef2016-07-20 06:04:34 -07001297
reed@google.com4e2b3d32011-04-07 14:18:59 +00001298 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299}
1300
reed32704672015-12-16 08:27:10 -08001301/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001302
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001303void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001304 if (dx || dy) {
1305 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001306 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001307
reedfe69b502016-09-12 06:31:48 -07001308 // Translate shouldn't affect the is-scale-translateness of the matrix.
1309 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001310
Mike Reedc42a1cd2017-02-14 14:25:14 -05001311 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001312
reedfe69b502016-09-12 06:31:48 -07001313 this->didTranslate(dx,dy);
1314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315}
1316
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001317void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001318 SkMatrix m;
1319 m.setScale(sx, sy);
1320 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321}
1322
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001323void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001324 SkMatrix m;
1325 m.setRotate(degrees);
1326 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001327}
1328
bungeman7438bfc2016-07-12 15:01:19 -07001329void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1330 SkMatrix m;
1331 m.setRotate(degrees, px, py);
1332 this->concat(m);
1333}
1334
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001335void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001336 SkMatrix m;
1337 m.setSkew(sx, sy);
1338 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001339}
1340
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001341void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001342 if (matrix.isIdentity()) {
1343 return;
1344 }
1345
reed2ff1fce2014-12-11 07:07:37 -08001346 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001347 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001348 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001349
Mike Reed7627fa52017-02-08 10:07:53 -05001350 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001351
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001352 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001353}
1354
reed8c30a812016-04-20 16:36:51 -07001355void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001356 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001357 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001358
Mike Reedc42a1cd2017-02-14 14:25:14 -05001359 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001360}
1361
1362void SkCanvas::setMatrix(const SkMatrix& matrix) {
1363 this->checkForDeferredSave();
1364 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001365 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001366}
1367
reed@android.com8a1c16f2008-12-17 15:59:43 +00001368void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001369 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001370}
1371
1372//////////////////////////////////////////////////////////////////////////////
1373
Mike Reedc1f77742016-12-09 09:00:50 -05001374void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001375 if (!rect.isFinite()) {
1376 return;
1377 }
reed2ff1fce2014-12-11 07:07:37 -08001378 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001379 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1380 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001381}
1382
Mike Reedc1f77742016-12-09 09:00:50 -05001383void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001384 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001385
Mike Reed7627fa52017-02-08 10:07:53 -05001386 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001387
reedc64eff52015-11-21 12:39:45 -08001388 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001389 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1390 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001391 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001392}
1393
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001394void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1395 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001396 if (fClipRestrictionRect.isEmpty()) {
1397 // we notify the device, but we *dont* resolve deferred saves (since we're just
1398 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001399 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001400 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001401 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001402 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001403 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001404 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001405 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1406 }
1407}
1408
Mike Reedc1f77742016-12-09 09:00:50 -05001409void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001410 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001411 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001412 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001413 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1414 } else {
1415 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001416 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001417}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001418
Mike Reedc1f77742016-12-09 09:00:50 -05001419void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001420 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001421
Brian Salomona3b45d42016-10-03 11:36:16 -04001422 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001423
Mike Reed7627fa52017-02-08 10:07:53 -05001424 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001425
Mike Reed20800c82017-11-15 16:09:04 -05001426 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1427 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001428 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001429}
1430
Mike Reedc1f77742016-12-09 09:00:50 -05001431void SkCanvas::clipPath(const SkPath& path, 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;
robertphillips39f05382015-11-24 09:30:12 -08001434
1435 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1436 SkRect r;
1437 if (path.isRect(&r)) {
1438 this->onClipRect(r, op, edgeStyle);
1439 return;
1440 }
1441 SkRRect rrect;
1442 if (path.isOval(&r)) {
1443 rrect.setOval(r);
1444 this->onClipRRect(rrect, op, edgeStyle);
1445 return;
1446 }
1447 if (path.isRRect(&rrect)) {
1448 this->onClipRRect(rrect, op, edgeStyle);
1449 return;
1450 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001451 }
robertphillips39f05382015-11-24 09:30:12 -08001452
1453 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001454}
1455
Mike Reedc1f77742016-12-09 09:00:50 -05001456void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001457 AutoValidateClip avc(this);
1458
Brian Salomona3b45d42016-10-03 11:36:16 -04001459 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001460
Mike Reed7627fa52017-02-08 10:07:53 -05001461 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001462
Brian Salomona3b45d42016-10-03 11:36:16 -04001463 const SkPath* rasterClipPath = &path;
1464 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001465 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1466 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001467 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468}
1469
Mike Reedc1f77742016-12-09 09:00:50 -05001470void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001471 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001472 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001473}
1474
Mike Reedc1f77742016-12-09 09:00:50 -05001475void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001476 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001477
reed@google.com5c3d1472011-02-22 19:12:23 +00001478 AutoValidateClip avc(this);
1479
Mike Reed20800c82017-11-15 16:09:04 -05001480 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001481 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482}
1483
reed@google.com819c9212011-02-23 18:56:55 +00001484#ifdef SK_DEBUG
1485void SkCanvas::validateClip() const {
1486 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001487 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001488 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001489 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001490 return;
1491 }
reed@google.com819c9212011-02-23 18:56:55 +00001492}
1493#endif
1494
Mike Reeda1361362017-03-07 09:37:29 -05001495bool SkCanvas::androidFramework_isClipAA() const {
1496 bool containsAA = false;
1497
1498 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1499
1500 return containsAA;
1501}
1502
1503class RgnAccumulator {
1504 SkRegion* fRgn;
1505public:
1506 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1507 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1508 SkIPoint origin = device->getOrigin();
1509 if (origin.x() | origin.y()) {
1510 rgn->translate(origin.x(), origin.y());
1511 }
1512 fRgn->op(*rgn, SkRegion::kUnion_Op);
1513 }
1514};
1515
1516void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1517 RgnAccumulator accum(rgn);
1518 SkRegion tmp;
1519
1520 rgn->setEmpty();
1521 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001522}
1523
reed@google.com5c3d1472011-02-22 19:12:23 +00001524///////////////////////////////////////////////////////////////////////////////
1525
reed@google.com754de5f2014-02-24 19:38:20 +00001526bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001527 return fMCRec->fRasterClip.isEmpty();
1528
1529 // TODO: should we only use the conservative answer in a recording canvas?
1530#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001531 SkBaseDevice* dev = this->getTopDevice();
1532 // if no device we return true
1533 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001534#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001535}
1536
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001537bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001538 SkBaseDevice* dev = this->getTopDevice();
1539 // if no device we return false
1540 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001541}
1542
msarettfbfa2582016-08-12 08:29:08 -07001543static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1544#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1545 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1546 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1547 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1548 return 0xF != _mm_movemask_ps(mask);
1549#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1550 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1551 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1552 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1553 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1554#else
1555 SkRect devRectAsRect;
1556 SkRect devClipAsRect;
1557 devRect.store(&devRectAsRect.fLeft);
1558 devClip.store(&devClipAsRect.fLeft);
1559 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1560#endif
1561}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001562
msarettfbfa2582016-08-12 08:29:08 -07001563// It's important for this function to not be inlined. Otherwise the compiler will share code
1564// between the fast path and the slow path, resulting in two slow paths.
1565static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1566 const SkMatrix& matrix) {
1567 SkRect deviceRect;
1568 matrix.mapRect(&deviceRect, src);
1569 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1570}
1571
1572bool SkCanvas::quickReject(const SkRect& src) const {
1573#ifdef SK_DEBUG
1574 // Verify that fDeviceClipBounds are set properly.
1575 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001576 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001577 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001578 } else {
msarettfbfa2582016-08-12 08:29:08 -07001579 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001580 }
msarettfbfa2582016-08-12 08:29:08 -07001581
msarett9637ea92016-08-18 14:03:30 -07001582 // Verify that fIsScaleTranslate is set properly.
1583 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001584#endif
1585
msarett9637ea92016-08-18 14:03:30 -07001586 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001587 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1588 }
1589
1590 // We inline the implementation of mapScaleTranslate() for the fast path.
1591 float sx = fMCRec->fMatrix.getScaleX();
1592 float sy = fMCRec->fMatrix.getScaleY();
1593 float tx = fMCRec->fMatrix.getTranslateX();
1594 float ty = fMCRec->fMatrix.getTranslateY();
1595 Sk4f scale(sx, sy, sx, sy);
1596 Sk4f trans(tx, ty, tx, ty);
1597
1598 // Apply matrix.
1599 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1600
1601 // Make sure left < right, top < bottom.
1602 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1603 Sk4f min = Sk4f::Min(ltrb, rblt);
1604 Sk4f max = Sk4f::Max(ltrb, rblt);
1605 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1606 // ARM this sequence generates the fastest (a single instruction).
1607 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1608
1609 // Check if the device rect is NaN or outside the clip.
1610 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001611}
1612
reed@google.com3b3e8952012-08-16 20:53:31 +00001613bool SkCanvas::quickReject(const SkPath& path) const {
1614 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001615}
1616
Mike Klein83c8dd92017-11-28 17:08:45 -05001617SkRect SkCanvas::getLocalClipBounds() const {
1618 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001619 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001620 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001621 }
1622
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001623 SkMatrix inverse;
1624 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001625 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001626 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001627 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001628
Mike Reed42e8c532017-01-23 14:09:13 -05001629 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001630 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001631 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001632
Mike Reedb57b9312018-04-23 12:12:54 -04001633 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001634 inverse.mapRect(&bounds, r);
1635 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001636}
1637
Mike Klein83c8dd92017-11-28 17:08:45 -05001638SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001639 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001640}
1641
reed@android.com8a1c16f2008-12-17 15:59:43 +00001642const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001643 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001644}
1645
Brian Osman11052242016-10-27 14:47:55 -04001646GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001647 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001648 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001649}
1650
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001651GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001652 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001653 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001654}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001655
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001656void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1657 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001658 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001659 if (outer.isEmpty()) {
1660 return;
1661 }
1662 if (inner.isEmpty()) {
1663 this->drawRRect(outer, paint);
1664 return;
1665 }
1666
1667 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001668 // be able to return ...
1669 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001670 //
1671 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001672 if (!outer.getBounds().contains(inner.getBounds())) {
1673 return;
1674 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001675
1676 this->onDrawDRRect(outer, inner, paint);
1677}
1678
reed41af9662015-01-05 07:49:08 -08001679void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001680 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001681 this->onDrawPaint(paint);
1682}
1683
1684void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001685 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001686 // To avoid redundant logic in our culling code and various backends, we always sort rects
1687 // before passing them along.
1688 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001689}
1690
msarettdca352e2016-08-26 06:37:45 -07001691void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001692 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001693 if (region.isEmpty()) {
1694 return;
1695 }
1696
1697 if (region.isRect()) {
1698 return this->drawIRect(region.getBounds(), paint);
1699 }
1700
1701 this->onDrawRegion(region, paint);
1702}
1703
reed41af9662015-01-05 07:49:08 -08001704void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001705 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001706 // To avoid redundant logic in our culling code and various backends, we always sort rects
1707 // before passing them along.
1708 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001709}
1710
1711void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001712 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001713 this->onDrawRRect(rrect, paint);
1714}
1715
1716void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001717 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001718 this->onDrawPoints(mode, count, pts, paint);
1719}
1720
Mike Reede88a1cb2017-03-17 09:50:46 -04001721void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1722 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001723 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001724 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001725 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1726 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001727 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001728}
1729
1730void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001731 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001732 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001733 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1734}
1735
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001736void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1737 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001738 TRACE_EVENT0("skia", TRACE_FUNC);
1739 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001740 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001741 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1742}
1743
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001744void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1745 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001746 TRACE_EVENT0("skia", TRACE_FUNC);
1747 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001748 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001749 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001750}
1751
1752void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001753 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001754 this->onDrawPath(path, paint);
1755}
1756
reeda85d4d02015-05-06 12:56:48 -07001757void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001758 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001759 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001760 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001761}
1762
Mike Reedc4e31092018-01-30 11:15:27 -05001763// Returns true if the rect can be "filled" : non-empty and finite
1764static bool fillable(const SkRect& r) {
1765 SkScalar w = r.width();
1766 SkScalar h = r.height();
1767 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1768}
1769
reede47829b2015-08-06 10:02:53 -07001770void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1771 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001772 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001773 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001774 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001775 return;
1776 }
1777 this->onDrawImageRect(image, &src, dst, paint, constraint);
1778}
reed41af9662015-01-05 07:49:08 -08001779
reed84984ef2015-07-17 07:09:43 -07001780void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1781 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001782 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001783 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001784}
1785
Brian Salomonf08002c2018-10-26 16:15:46 -04001786void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001787 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001788 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001789 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001790}
reede47829b2015-08-06 10:02:53 -07001791
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001792namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001793class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001794public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001795 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1796 if (!origPaint) {
1797 return;
1798 }
1799 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1800 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1801 }
1802 if (origPaint->getMaskFilter()) {
1803 fPaint.writable()->setMaskFilter(nullptr);
1804 }
1805 if (origPaint->isAntiAlias()) {
1806 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001807 }
1808 }
1809
1810 const SkPaint* get() const {
1811 return fPaint;
1812 }
1813
1814private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001815 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001816};
1817} // namespace
1818
reed4c21dc52015-06-25 12:32:03 -07001819void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1820 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001821 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001822 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001823 if (dst.isEmpty()) {
1824 return;
1825 }
msarett552bca92016-08-03 06:53:26 -07001826 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001827 LatticePaint latticePaint(paint);
1828 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001829 } else {
reede47829b2015-08-06 10:02:53 -07001830 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001831 }
reed4c21dc52015-06-25 12:32:03 -07001832}
1833
msarett16882062016-08-16 09:31:08 -07001834void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1835 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001836 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001837 RETURN_ON_NULL(image);
1838 if (dst.isEmpty()) {
1839 return;
1840 }
msarett71df2d72016-09-30 12:41:42 -07001841
1842 SkIRect bounds;
1843 Lattice latticePlusBounds = lattice;
1844 if (!latticePlusBounds.fBounds) {
1845 bounds = SkIRect::MakeWH(image->width(), image->height());
1846 latticePlusBounds.fBounds = &bounds;
1847 }
1848
1849 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001850 LatticePaint latticePaint(paint);
1851 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001852 } else {
1853 this->drawImageRect(image, dst, paint);
1854 }
1855}
1856
Brian Salomon1da5cad2018-11-21 09:21:18 -05001857void SkCanvas::experimental_DrawImageSetV1(const ImageSetEntry imageSet[], int cnt,
1858 SkFilterQuality filterQuality, SkBlendMode mode) {
1859 TRACE_EVENT0("skia", TRACE_FUNC);
1860 RETURN_ON_NULL(imageSet);
1861 RETURN_ON_FALSE(cnt);
1862
Brian Salomond003d222018-11-26 13:25:05 -05001863 this->onDrawImageSet(imageSet, cnt, filterQuality, mode);
Brian Salomon1da5cad2018-11-21 09:21:18 -05001864}
1865
Michael Ludwig75451902019-01-23 11:14:29 -05001866void SkCanvas::experimental_DrawEdgeAARectV1(const SkRect& r, QuadAAFlags edgeAA, SkColor color,
1867 SkBlendMode mode) {
1868 TRACE_EVENT0("skia", TRACE_FUNC);
1869 // To avoid redundant logic in our culling code and various backends, we always sort rects
1870 // before passing them along.
1871 this->onDrawEdgeAARect(r.makeSorted(), edgeAA, color, mode);
1872}
1873
reed41af9662015-01-05 07:49:08 -08001874void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001875 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001876 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001877 return;
1878 }
reed41af9662015-01-05 07:49:08 -08001879 this->onDrawBitmap(bitmap, dx, dy, paint);
1880}
1881
reede47829b2015-08-06 10:02:53 -07001882void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001883 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001884 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001885 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001886 return;
1887 }
reede47829b2015-08-06 10:02:53 -07001888 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001889}
1890
reed84984ef2015-07-17 07:09:43 -07001891void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1892 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001893 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001894}
1895
reede47829b2015-08-06 10:02:53 -07001896void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1897 SrcRectConstraint constraint) {
1898 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1899 constraint);
1900}
reede47829b2015-08-06 10:02:53 -07001901
reed41af9662015-01-05 07:49:08 -08001902void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1903 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001904 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001905 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001906 return;
1907 }
msarett552bca92016-08-03 06:53:26 -07001908 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001909 LatticePaint latticePaint(paint);
1910 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001911 } else {
reeda5517e22015-07-14 10:54:12 -07001912 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001913 }
reed41af9662015-01-05 07:49:08 -08001914}
1915
msarettc573a402016-08-02 08:05:56 -07001916void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1917 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001918 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001919 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001920 return;
1921 }
msarett71df2d72016-09-30 12:41:42 -07001922
1923 SkIRect bounds;
1924 Lattice latticePlusBounds = lattice;
1925 if (!latticePlusBounds.fBounds) {
1926 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1927 latticePlusBounds.fBounds = &bounds;
1928 }
1929
1930 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001931 LatticePaint latticePaint(paint);
1932 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001933 } else {
msarett16882062016-08-16 09:31:08 -07001934 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001935 }
msarettc573a402016-08-02 08:05:56 -07001936}
1937
reed71c3c762015-06-24 10:29:17 -07001938void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001939 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001940 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001941 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001942 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001943 if (count <= 0) {
1944 return;
1945 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001946 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001947 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001948 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001949}
1950
reedf70b5312016-03-04 16:36:20 -08001951void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001952 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001953 if (key) {
1954 this->onDrawAnnotation(rect, key, value);
1955 }
1956}
1957
reede47829b2015-08-06 10:02:53 -07001958void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1959 const SkPaint* paint, SrcRectConstraint constraint) {
1960 if (src) {
1961 this->drawImageRect(image, *src, dst, paint, constraint);
1962 } else {
1963 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1964 dst, paint, constraint);
1965 }
1966}
1967void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1968 const SkPaint* paint, SrcRectConstraint constraint) {
1969 if (src) {
1970 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1971 } else {
1972 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1973 dst, paint, constraint);
1974 }
1975}
1976
Mike Reed4204da22017-05-17 08:53:36 -04001977void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001978 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001979 this->onDrawShadowRec(path, rec);
1980}
1981
1982void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1983 SkPaint paint;
1984 const SkRect& pathBounds = path.getBounds();
1985
Ben Wagner2c312c42018-06-27 14:46:46 -04001986 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001987 while (iter.next()) {
1988 iter.fDevice->drawShadow(path, rec);
1989 }
1990 LOOPER_END
1991}
1992
reed@android.com8a1c16f2008-12-17 15:59:43 +00001993//////////////////////////////////////////////////////////////////////////////
1994// These are the virtual drawing methods
1995//////////////////////////////////////////////////////////////////////////////
1996
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001997void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001998 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001999 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2000 }
2001}
2002
reed41af9662015-01-05 07:49:08 -08002003void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002004 this->internalDrawPaint(paint);
2005}
2006
2007void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002008 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002009
2010 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002011 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002012 }
2013
reed@google.com4e2b3d32011-04-07 14:18:59 +00002014 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002015}
2016
reed41af9662015-01-05 07:49:08 -08002017void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2018 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002019 if ((long)count <= 0) {
2020 return;
2021 }
2022
Mike Reed822128b2017-02-28 16:41:03 -05002023 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002024 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002025 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002026 // special-case 2 points (common for drawing a single line)
2027 if (2 == count) {
2028 r.set(pts[0], pts[1]);
2029 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002030 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002031 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002032 if (!r.isFinite()) {
2033 return;
2034 }
Mike Reed822128b2017-02-28 16:41:03 -05002035 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002036 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2037 return;
2038 }
2039 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002040 }
reed@google.coma584aed2012-05-16 14:06:02 +00002041
halcanary96fcdcc2015-08-27 07:41:13 -07002042 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002043
Ben Wagner2c312c42018-06-27 14:46:46 -04002044 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002045
reed@android.com8a1c16f2008-12-17 15:59:43 +00002046 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002047 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002048 }
reed@google.com4b226022011-01-11 18:32:13 +00002049
reed@google.com4e2b3d32011-04-07 14:18:59 +00002050 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002051}
2052
reed4a167172016-08-18 17:15:25 -07002053static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2054 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07002055 (intptr_t)paint.getLooper() ) != 0;
2056}
2057
reed41af9662015-01-05 07:49:08 -08002058void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002059 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002060 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002061 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002062 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002063 return;
2064 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002065 }
reed@google.com4b226022011-01-11 18:32:13 +00002066
reed4a167172016-08-18 17:15:25 -07002067 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002068 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002069
reed4a167172016-08-18 17:15:25 -07002070 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002071 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002072 }
2073
2074 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002075 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002076 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002077 SkDrawIter iter(this);
2078 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002079 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002080 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002081 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002082}
2083
Michael Ludwig75451902019-01-23 11:14:29 -05002084void SkCanvas::onDrawEdgeAARect(const SkRect& r, QuadAAFlags edgeAA, SkColor color,
2085 SkBlendMode mode) {
2086 SkASSERT(r.isSorted());
2087
2088 SkPaint paint;
2089 LOOPER_BEGIN(paint, nullptr)
2090
2091 while (iter.next()) {
2092 iter.fDevice->drawEdgeAARect(r, edgeAA, color, mode);
2093 }
2094
2095 LOOPER_END
2096}
2097
msarett44df6512016-08-25 13:54:30 -07002098void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002099 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002100 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002101 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002102 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2103 return;
2104 }
msarett44df6512016-08-25 13:54:30 -07002105 }
2106
Ben Wagner2c312c42018-06-27 14:46:46 -04002107 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002108
2109 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002110 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002111 }
2112
2113 LOOPER_END
2114}
2115
reed41af9662015-01-05 07:49:08 -08002116void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002117 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002118 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002119 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002120 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002121 return;
2122 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002123 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002124
Ben Wagner2c312c42018-06-27 14:46:46 -04002125 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002126
2127 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002128 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002129 }
2130
2131 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002132}
2133
bsalomonac3aa242016-08-19 11:25:19 -07002134void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2135 SkScalar sweepAngle, bool useCenter,
2136 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002137 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002138 if (paint.canComputeFastBounds()) {
2139 SkRect storage;
2140 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002141 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002142 return;
2143 }
bsalomonac3aa242016-08-19 11:25:19 -07002144 }
2145
Ben Wagner2c312c42018-06-27 14:46:46 -04002146 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002147
2148 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002149 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002150 }
2151
2152 LOOPER_END
2153}
2154
reed41af9662015-01-05 07:49:08 -08002155void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002156 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002157 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002158 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2159 return;
2160 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002161 }
2162
2163 if (rrect.isRect()) {
2164 // call the non-virtual version
2165 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002166 return;
2167 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002168 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002169 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2170 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002171 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002172
Ben Wagner2c312c42018-06-27 14:46:46 -04002173 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002174
2175 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002176 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002177 }
2178
2179 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002180}
2181
Mike Reed822128b2017-02-28 16:41:03 -05002182void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002183 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002184 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002185 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2186 return;
2187 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002188 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002189
Ben Wagner2c312c42018-06-27 14:46:46 -04002190 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002191
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002192 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002193 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002194 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002195
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002196 LOOPER_END
2197}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002198
reed41af9662015-01-05 07:49:08 -08002199void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002200 if (!path.isFinite()) {
2201 return;
2202 }
2203
Mike Reed822128b2017-02-28 16:41:03 -05002204 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002205 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002206 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002207 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2208 return;
2209 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002210 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002211
Mike Reed822128b2017-02-28 16:41:03 -05002212 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002213 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002214 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002215 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002216 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002217 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002218
Ben Wagner2c312c42018-06-27 14:46:46 -04002219 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002220
2221 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002222 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002223 }
2224
reed@google.com4e2b3d32011-04-07 14:18:59 +00002225 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002226}
2227
reed262a71b2015-12-05 13:07:27 -08002228bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002229 if (!paint.getImageFilter()) {
2230 return false;
2231 }
2232
2233 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002234 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002235 return false;
2236 }
2237
2238 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2239 // Once we can filter and the filter will return a result larger than itself, we should be
2240 // able to remove this constraint.
2241 // skbug.com/4526
2242 //
2243 SkPoint pt;
2244 ctm.mapXY(x, y, &pt);
2245 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2246 return ir.contains(fMCRec->fRasterClip.getBounds());
2247}
2248
Mike Reedf441cfc2018-04-11 14:50:16 -04002249// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2250// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2251// null.
2252static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2253 if (paintParam) {
2254 *real = *paintParam;
2255 real->setStyle(SkPaint::kFill_Style);
2256 real->setPathEffect(nullptr);
2257 paintParam = real;
2258 }
2259 return paintParam;
2260}
2261
reeda85d4d02015-05-06 12:56:48 -07002262void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002263 SkPaint realPaint;
2264 paint = init_image_paint(&realPaint, paint);
2265
reeda85d4d02015-05-06 12:56:48 -07002266 SkRect bounds = SkRect::MakeXYWH(x, y,
2267 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002268 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002269 SkRect tmp = bounds;
2270 if (paint) {
2271 paint->computeFastBounds(tmp, &tmp);
2272 }
2273 if (this->quickReject(tmp)) {
2274 return;
2275 }
reeda85d4d02015-05-06 12:56:48 -07002276 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002277 // At this point we need a real paint object. If the caller passed null, then we should
2278 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2279 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2280 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002281
reeda2217ef2016-07-20 06:04:34 -07002282 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002283 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2284 *paint);
2285 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002286 special = this->getDevice()->makeSpecial(image);
2287 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002288 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002289 }
2290 }
2291
reed262a71b2015-12-05 13:07:27 -08002292 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2293
reeda85d4d02015-05-06 12:56:48 -07002294 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002295 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002296 if (special) {
2297 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002298 iter.fDevice->ctm().mapXY(x, y, &pt);
2299 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002300 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002301 SkScalarRoundToInt(pt.fY), pnt,
2302 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002303 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002304 iter.fDevice->drawImageRect(
2305 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2306 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002307 }
reeda85d4d02015-05-06 12:56:48 -07002308 }
halcanary9d524f22016-03-29 09:03:52 -07002309
reeda85d4d02015-05-06 12:56:48 -07002310 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002311}
2312
reed41af9662015-01-05 07:49:08 -08002313void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002314 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002315 SkPaint realPaint;
2316 paint = init_image_paint(&realPaint, paint);
2317
halcanary96fcdcc2015-08-27 07:41:13 -07002318 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002319 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002320 if (paint) {
2321 paint->computeFastBounds(dst, &storage);
2322 }
2323 if (this->quickReject(storage)) {
2324 return;
2325 }
reeda85d4d02015-05-06 12:56:48 -07002326 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002327 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002328
Ben Wagner2c312c42018-06-27 14:46:46 -04002329 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002330
reeda85d4d02015-05-06 12:56:48 -07002331 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002332 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002333 }
halcanary9d524f22016-03-29 09:03:52 -07002334
reeda85d4d02015-05-06 12:56:48 -07002335 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002336}
2337
reed41af9662015-01-05 07:49:08 -08002338void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002339 SkDEBUGCODE(bitmap.validate();)
2340
reed33366972015-10-08 09:22:02 -07002341 if (bitmap.drawsNothing()) {
2342 return;
2343 }
2344
Mike Reedf441cfc2018-04-11 14:50:16 -04002345 SkPaint realPaint;
2346 init_image_paint(&realPaint, paint);
2347 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002348
Mike Reed822128b2017-02-28 16:41:03 -05002349 SkRect bounds;
2350 bitmap.getBounds(&bounds);
2351 bounds.offset(x, y);
2352 bool canFastBounds = paint->canComputeFastBounds();
2353 if (canFastBounds) {
2354 SkRect storage;
2355 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002356 return;
2357 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002358 }
reed@google.com4b226022011-01-11 18:32:13 +00002359
reeda2217ef2016-07-20 06:04:34 -07002360 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002361 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2362 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002363 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002364 special = this->getDevice()->makeSpecial(bitmap);
2365 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002366 drawAsSprite = false;
2367 }
2368 }
2369
Mike Reed822128b2017-02-28 16:41:03 -05002370 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002371
2372 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002373 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002374 if (special) {
reed262a71b2015-12-05 13:07:27 -08002375 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002376 iter.fDevice->ctm().mapXY(x, y, &pt);
2377 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002378 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002379 SkScalarRoundToInt(pt.fY), pnt,
2380 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002381 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002382 SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2383 iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2384 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002385 }
reed33366972015-10-08 09:22:02 -07002386 }
msarettfbfa2582016-08-12 08:29:08 -07002387
reed33366972015-10-08 09:22:02 -07002388 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002389}
2390
reed@google.com9987ec32011-09-07 11:57:52 +00002391// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002392void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002393 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002394 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002395 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002396 return;
2397 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002398
halcanary96fcdcc2015-08-27 07:41:13 -07002399 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002400 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002401 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2402 return;
2403 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002404 }
reed@google.com3d608122011-11-21 15:16:16 +00002405
reed@google.com33535f32012-09-25 15:37:50 +00002406 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002407 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002408 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002409 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002410
Ben Wagner2c312c42018-06-27 14:46:46 -04002411 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002412
reed@google.com33535f32012-09-25 15:37:50 +00002413 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002414 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002415 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002416
reed@google.com33535f32012-09-25 15:37:50 +00002417 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002418}
2419
reed41af9662015-01-05 07:49:08 -08002420void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002421 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002422 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002423 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002424}
2425
reed4c21dc52015-06-25 12:32:03 -07002426void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2427 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002428 SkPaint realPaint;
2429 paint = init_image_paint(&realPaint, paint);
2430
halcanary96fcdcc2015-08-27 07:41:13 -07002431 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002432 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002433 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2434 return;
2435 }
reed@google.com3d608122011-11-21 15:16:16 +00002436 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002437 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002438
Ben Wagner2c312c42018-06-27 14:46:46 -04002439 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002440
reed4c21dc52015-06-25 12:32:03 -07002441 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002442 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002443 }
halcanary9d524f22016-03-29 09:03:52 -07002444
reed4c21dc52015-06-25 12:32:03 -07002445 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002446}
2447
reed41af9662015-01-05 07:49:08 -08002448void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2449 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002450 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002451 SkPaint realPaint;
2452 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002453
halcanary96fcdcc2015-08-27 07:41:13 -07002454 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002455 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002456 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2457 return;
2458 }
reed4c21dc52015-06-25 12:32:03 -07002459 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002460 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002461
Ben Wagner2c312c42018-06-27 14:46:46 -04002462 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002463
reed4c21dc52015-06-25 12:32:03 -07002464 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002465 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002466 }
halcanary9d524f22016-03-29 09:03:52 -07002467
reed4c21dc52015-06-25 12:32:03 -07002468 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002469}
2470
msarett16882062016-08-16 09:31:08 -07002471void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2472 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002473 SkPaint realPaint;
2474 paint = init_image_paint(&realPaint, paint);
2475
msarett16882062016-08-16 09:31:08 -07002476 if (nullptr == paint || paint->canComputeFastBounds()) {
2477 SkRect storage;
2478 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2479 return;
2480 }
2481 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002482 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002483
Ben Wagner2c312c42018-06-27 14:46:46 -04002484 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002485
2486 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002487 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002488 }
2489
2490 LOOPER_END
2491}
2492
Brian Salomond003d222018-11-26 13:25:05 -05002493void SkCanvas::onDrawImageSet(const ImageSetEntry imageSet[], int count,
Brian Salomond7065e72018-10-12 11:42:02 -04002494 SkFilterQuality filterQuality, SkBlendMode mode) {
2495 SkPaint paint;
Brian Salomon23356442018-11-30 15:33:19 -05002496 LOOPER_BEGIN(paint, nullptr)
Brian Salomond7065e72018-10-12 11:42:02 -04002497 while (iter.next()) {
Brian Salomond003d222018-11-26 13:25:05 -05002498 iter.fDevice->drawImageSet(imageSet, count, filterQuality, mode);
Brian Salomond7065e72018-10-12 11:42:02 -04002499 }
2500 LOOPER_END
2501}
2502
msarett16882062016-08-16 09:31:08 -07002503void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2504 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002505 SkPaint realPaint;
2506 paint = init_image_paint(&realPaint, paint);
2507
msarett16882062016-08-16 09:31:08 -07002508 if (nullptr == paint || paint->canComputeFastBounds()) {
2509 SkRect storage;
2510 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2511 return;
2512 }
2513 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002514 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002515
Ben Wagner2c312c42018-06-27 14:46:46 -04002516 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002517
2518 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002519 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002520 }
2521
2522 LOOPER_END
2523}
2524
fmalita00d5c2c2014-08-21 08:53:26 -07002525void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2526 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002527 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002528 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002529 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002530 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002531 SkRect tmp;
2532 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2533 return;
2534 }
2535 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002536 }
2537
fmalita024f9962015-03-03 19:08:17 -08002538 // We cannot filter in the looper as we normally do, because the paint is
2539 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002540 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002541
fmalitaaa1b9122014-08-28 14:32:24 -07002542 while (iter.next()) {
Mike Reed30cf62b2018-12-20 11:18:24 -05002543 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002544 }
2545
fmalitaaa1b9122014-08-28 14:32:24 -07002546 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002547}
2548
Mike Reed358fcad2018-11-23 15:27:51 -05002549// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002550void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002551 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2552 TRACE_EVENT0("skia", TRACE_FUNC);
2553 if (byteLength) {
2554 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002555 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002556 }
2557}
Mike Reed4f81bb72019-01-23 09:23:00 -05002558
fmalita00d5c2c2014-08-21 08:53:26 -07002559void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2560 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002561 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002562 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002563 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002564 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002565}
reed@google.come0d9ce82014-04-23 04:00:17 +00002566
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002567void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002568 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002569 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002570
2571 while (iter.next()) {
2572 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002573 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002574 }
2575
2576 LOOPER_END
2577}
2578
dandovb3c9d1c2014-08-12 08:34:29 -07002579void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002580 const SkPoint texCoords[4], SkBlendMode bmode,
2581 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002582 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002583 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002584 return;
2585 }
mtklein6cfa73a2014-08-13 13:33:49 -07002586
Mike Reedfaba3712016-11-03 14:45:31 -04002587 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002588}
2589
2590void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002591 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002592 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002593 // Since a patch is always within the convex hull of the control points, we discard it when its
2594 // bounding rectangle is completely outside the current clip.
2595 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002596 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002597 if (this->quickReject(bounds)) {
2598 return;
2599 }
mtklein6cfa73a2014-08-13 13:33:49 -07002600
Ben Wagner2c312c42018-06-27 14:46:46 -04002601 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002602
dandovecfff212014-08-04 10:02:00 -07002603 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002604 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002605 }
mtklein6cfa73a2014-08-13 13:33:49 -07002606
dandovecfff212014-08-04 10:02:00 -07002607 LOOPER_END
2608}
2609
reeda8db7282015-07-07 10:22:31 -07002610void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002611#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002612 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002613#endif
reede3b38ce2016-01-08 09:18:44 -08002614 RETURN_ON_NULL(dr);
2615 if (x || y) {
2616 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2617 this->onDrawDrawable(dr, &matrix);
2618 } else {
2619 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002620 }
2621}
2622
reeda8db7282015-07-07 10:22:31 -07002623void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002624#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002625 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002626#endif
reede3b38ce2016-01-08 09:18:44 -08002627 RETURN_ON_NULL(dr);
2628 if (matrix && matrix->isIdentity()) {
2629 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002630 }
reede3b38ce2016-01-08 09:18:44 -08002631 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002632}
2633
2634void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002635 // drawable bounds are no longer reliable (e.g. android displaylist)
2636 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002637 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002638}
2639
reed71c3c762015-06-24 10:29:17 -07002640void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002641 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002642 const SkRect* cull, const SkPaint* paint) {
2643 if (cull && this->quickReject(*cull)) {
2644 return;
2645 }
2646
2647 SkPaint pnt;
2648 if (paint) {
2649 pnt = *paint;
2650 }
halcanary9d524f22016-03-29 09:03:52 -07002651
Ben Wagner2c312c42018-06-27 14:46:46 -04002652 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002653 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002654 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002655 }
2656 LOOPER_END
2657}
2658
reedf70b5312016-03-04 16:36:20 -08002659void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2660 SkASSERT(key);
2661
2662 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002663 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002664 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002665 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002666 }
2667 LOOPER_END
2668}
2669
reed@android.com8a1c16f2008-12-17 15:59:43 +00002670//////////////////////////////////////////////////////////////////////////////
2671// These methods are NOT virtual, and therefore must call back into virtual
2672// methods, rather than actually drawing themselves.
2673//////////////////////////////////////////////////////////////////////////////
2674
reed374772b2016-10-05 17:33:02 -07002675void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002676 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002677 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002678 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002679 this->drawPaint(paint);
2680}
2681
2682void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002683 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002684 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2685}
2686
Mike Reed3661bc92017-02-22 13:21:42 -05002687void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002688 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002689 pts[0].set(x0, y0);
2690 pts[1].set(x1, y1);
2691 this->drawPoints(kLines_PointMode, 2, pts, paint);
2692}
2693
Mike Reed3661bc92017-02-22 13:21:42 -05002694void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002695 if (radius < 0) {
2696 radius = 0;
2697 }
2698
2699 SkRect r;
2700 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002701 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002702}
2703
2704void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2705 const SkPaint& paint) {
2706 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002707 SkRRect rrect;
2708 rrect.setRectXY(r, rx, ry);
2709 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002710 } else {
2711 this->drawRect(r, paint);
2712 }
2713}
2714
reed@android.com8a1c16f2008-12-17 15:59:43 +00002715void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2716 SkScalar sweepAngle, bool useCenter,
2717 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002718 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002719 if (oval.isEmpty() || !sweepAngle) {
2720 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002721 }
bsalomon21af9ca2016-08-25 12:29:23 -07002722 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723}
2724
reed@android.comf76bacf2009-05-13 14:00:33 +00002725///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002726#ifdef SK_DISABLE_SKPICTURE
2727void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002728
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002729
2730void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2731 const SkPaint* paint) {}
2732#else
Mike Klein88d90712018-01-27 17:30:04 +00002733/**
2734 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2735 * against the playback cost of recursing into the subpicture to get at its actual ops.
2736 *
2737 * For now we pick a conservatively small value, though measurement (and other heuristics like
2738 * the type of ops contained) may justify changing this value.
2739 */
2740#define kMaxPictureOpsToUnrollInsteadOfRef 1
2741
reedd5fa1a42014-08-09 11:08:05 -07002742void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002743 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002744 RETURN_ON_NULL(picture);
2745
reede3b38ce2016-01-08 09:18:44 -08002746 if (matrix && matrix->isIdentity()) {
2747 matrix = nullptr;
2748 }
Mike Klein88d90712018-01-27 17:30:04 +00002749 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2750 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2751 picture->playback(this);
2752 } else {
2753 this->onDrawPicture(picture, matrix, paint);
2754 }
reedd5fa1a42014-08-09 11:08:05 -07002755}
robertphillips9b14f262014-06-04 05:40:44 -07002756
reedd5fa1a42014-08-09 11:08:05 -07002757void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2758 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002759 if (!paint || paint->canComputeFastBounds()) {
2760 SkRect bounds = picture->cullRect();
2761 if (paint) {
2762 paint->computeFastBounds(bounds, &bounds);
2763 }
2764 if (matrix) {
2765 matrix->mapRect(&bounds);
2766 }
2767 if (this->quickReject(bounds)) {
2768 return;
2769 }
2770 }
2771
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002772 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002773 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002775#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777///////////////////////////////////////////////////////////////////////////////
2778///////////////////////////////////////////////////////////////////////////////
2779
reed3aafe112016-08-18 12:45:34 -07002780SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002781 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782
2783 SkASSERT(canvas);
2784
reed3aafe112016-08-18 12:45:34 -07002785 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786 fDone = !fImpl->next();
2787}
2788
2789SkCanvas::LayerIter::~LayerIter() {
2790 fImpl->~SkDrawIter();
2791}
2792
2793void SkCanvas::LayerIter::next() {
2794 fDone = !fImpl->next();
2795}
2796
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002797SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002798 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002799}
2800
2801const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002802 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002803}
2804
2805const SkPaint& SkCanvas::LayerIter::paint() const {
2806 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002807 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002808 paint = &fDefaultPaint;
2809 }
2810 return *paint;
2811}
2812
Mike Reedca37f322018-03-08 13:22:16 -05002813SkIRect SkCanvas::LayerIter::clipBounds() const {
2814 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002815}
2816
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2818int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002819
2820///////////////////////////////////////////////////////////////////////////////
2821
Mike Reed5df49342016-11-12 08:06:55 -06002822std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002823 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002824 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002825 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002826 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002827
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002828 SkBitmap bitmap;
2829 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002830 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002831 }
Mike Reed12f77342017-11-08 11:19:52 -05002832
2833 return props ?
2834 skstd::make_unique<SkCanvas>(bitmap, *props) :
2835 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002836}
reedd5fa1a42014-08-09 11:08:05 -07002837
2838///////////////////////////////////////////////////////////////////////////////
2839
Florin Malitaee424ac2016-12-01 12:47:59 -05002840SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002841 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002842
Florin Malita439ace92016-12-02 12:05:41 -05002843SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002844 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002845
Herb Derbyefe39bc2018-05-01 17:06:20 -04002846SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002847 : INHERITED(device) {}
2848
Florin Malitaee424ac2016-12-01 12:47:59 -05002849SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2850 (void)this->INHERITED::getSaveLayerStrategy(rec);
2851 return kNoLayer_SaveLayerStrategy;
2852}
2853
Mike Reed148b7fd2018-12-18 17:38:18 -05002854bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2855 return false;
2856}
2857
Florin Malitaee424ac2016-12-01 12:47:59 -05002858///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002859
reed73603f32016-09-20 08:42:38 -07002860static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2861static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2862static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2863static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2864static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2865static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002866
2867///////////////////////////////////////////////////////////////////////////////////////////////////
2868
2869SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2870 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002871 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002872 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2873 SkIPoint origin = dev->getOrigin();
2874 SkMatrix ctm = this->getTotalMatrix();
2875 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2876
2877 SkIRect clip = fMCRec->fRasterClip.getBounds();
2878 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002879 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002880 clip.setEmpty();
2881 }
2882
2883 fAllocator->updateHandle(handle, ctm, clip);
2884 return handle;
2885 }
2886 return nullptr;
2887}
2888
2889static bool install(SkBitmap* bm, const SkImageInfo& info,
2890 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002891 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002892}
2893
2894SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2895 SkBitmap* bm) {
2896 SkRasterHandleAllocator::Rec rec;
2897 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2898 return nullptr;
2899 }
2900 return rec.fHandle;
2901}
2902
2903std::unique_ptr<SkCanvas>
2904SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2905 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04002906 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05002907 return nullptr;
2908 }
2909
2910 SkBitmap bm;
2911 Handle hndl;
2912
2913 if (rec) {
2914 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2915 } else {
2916 hndl = alloc->allocBitmap(info, &bm);
2917 }
2918 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2919}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002920
2921///////////////////////////////////////////////////////////////////////////////////////////////////
2922
2923