blob: a8541d6b0bea461ee15047666e3d01f20a7a2ab1 [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
Mike Reed5532c2a2019-02-23 12:00:32 -0500976 // If we have a backdrop filter, then we must apply it to the entire layer (clip-bounds)
977 // regardless of any hint-rect from the caller. skbug.com/8783
978 if (rec.fBackdrop) {
979 bounds = nullptr;
980 }
981
reed8c30a812016-04-20 16:36:51 -0700982 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400983 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700984 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400985 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700986 SkMatrix remainder;
987 SkSize scale;
988 /*
989 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
990 * but they do handle scaling. To accommodate this, we do the following:
991 *
992 * 1. Stash off the current CTM
993 * 2. Decompose the CTM into SCALE and REMAINDER
994 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
995 * contains the REMAINDER
996 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
997 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
998 * of the original imagefilter, and draw that (via drawSprite)
999 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1000 *
1001 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1002 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1003 */
reed96a04f32016-04-25 09:25:15 -07001004 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001005 stashedMatrix.decomposeScale(&scale, &remainder))
1006 {
1007 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001008 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001009 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1010 SkPaint* p = lazyP.set(*paint);
1011 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1012 SkFilterQuality::kLow_SkFilterQuality,
1013 sk_ref_sp(imageFilter)));
1014 imageFilter = p->getImageFilter();
1015 paint = p;
1016 }
reed8c30a812016-04-20 16:36:51 -07001017
junov@chromium.orga907ac32012-02-24 21:54:07 +00001018 // do this before we create the layer. We don't call the public save() since
1019 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001020 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001021
junov@chromium.orga907ac32012-02-24 21:54:07 +00001022 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001023 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001024 if (modifiedRec) {
1025 // In this case there will be no layer in which to stash the matrix so we need to
1026 // revert the prior MCRec to its earlier state.
1027 modifiedRec->fMatrix = stashedMatrix;
1028 }
reed2ff1fce2014-12-11 07:07:37 -08001029 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001030 }
1031
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001032 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1033 // the clipRectBounds() call above?
1034 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001035 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001036 }
1037
reed8dc0ccb2015-03-20 06:32:52 -07001038 SkPixelGeometry geo = fProps.pixelGeometry();
1039 if (paint) {
reed76033be2015-03-14 10:54:31 -07001040 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001041 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001042 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001043 }
1044 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001045
robertphillips5139e502016-07-19 05:10:40 -07001046 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001047 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001048 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001049 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001050 }
reedb2db8982014-11-13 12:41:02 -08001051
Mike Kleine083f7c2018-02-07 12:54:27 -05001052 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001053
Hal Canary704cd322016-11-07 14:13:52 -05001054 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001055 {
Florin Malita07e4adf2019-01-07 16:34:18 -05001056 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType();
reeddaa57bf2015-05-15 10:39:17 -07001057 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001058 const bool trackCoverage =
1059 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001060 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001061 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001062 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001063 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001064 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1065 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001066 return;
reed61f501f2015-04-29 08:34:00 -07001067 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001068 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001069 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001070
Mike Reedb43a3e02017-02-11 10:18:58 -05001071 // only have a "next" if this new layer doesn't affect the clip (rare)
1072 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001073 fMCRec->fLayer = layer;
1074 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001075
Mike Reedc61abee2017-02-28 17:45:27 -05001076 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001077 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001078 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001079 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001080
Mike Reedc42a1cd2017-02-14 14:25:14 -05001081 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1082
1083 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1084 if (layer->fNext) {
1085 // need to punch a hole in the previous device, so we don't draw there, given that
1086 // the new top-layer will allow drawing to happen "below" it.
1087 SkRegion hole(ir);
1088 do {
1089 layer = layer->fNext;
1090 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1091 } while (layer->fNext);
1092 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093}
1094
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001095int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001096 if (0xFF == alpha) {
1097 return this->saveLayer(bounds, nullptr);
1098 } else {
1099 SkPaint tmpPaint;
1100 tmpPaint.setAlpha(alpha);
1101 return this->saveLayer(bounds, &tmpPaint);
1102 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001103}
1104
Mike Reed148b7fd2018-12-18 17:38:18 -05001105void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1106 SkIRect devBounds;
1107 if (localBounds) {
1108 SkRect tmp;
1109 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1110 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1111 devBounds.setEmpty();
1112 }
1113 } else {
1114 devBounds = this->getDeviceClipBounds();
1115 }
1116 if (devBounds.isEmpty()) {
1117 return;
1118 }
1119
1120 SkBaseDevice* device = this->getTopDevice();
1121 if (nullptr == device) { // Do we still need this check???
1122 return;
1123 }
1124
1125 // need the bounds relative to the device itself
1126 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1127
1128 auto backImage = device->snapBackImage(devBounds);
1129 if (!backImage) {
1130 return;
1131 }
1132
1133 // we really need the save, so we can wack the fMCRec
1134 this->checkForDeferredSave();
1135
1136 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1137
1138 SkPaint paint;
1139 paint.setBlendMode(SkBlendMode::kClear);
1140 if (localBounds) {
1141 this->drawRect(*localBounds, paint);
1142 } else {
1143 this->drawPaint(paint);
1144 }
1145}
1146
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147void SkCanvas::internalRestore() {
1148 SkASSERT(fMCStack.count() != 0);
1149
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001150 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001151 DeviceCM* layer = fMCRec->fLayer; // may be null
1152 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001153 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001154
Mike Reed148b7fd2018-12-18 17:38:18 -05001155 // move this out before we do the actual restore
1156 auto backImage = std::move(fMCRec->fBackImage);
1157
reed@android.com8a1c16f2008-12-17 15:59:43 +00001158 // now do the normal restore()
1159 fMCRec->~MCRec(); // balanced in save()
1160 fMCStack.pop_back();
1161 fMCRec = (MCRec*)fMCStack.back();
1162
Mike Reedc42a1cd2017-02-14 14:25:14 -05001163 if (fMCRec) {
1164 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1165 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001166
Mike Reed148b7fd2018-12-18 17:38:18 -05001167 if (backImage) {
1168 SkPaint paint;
1169 paint.setBlendMode(SkBlendMode::kDstOver);
1170 const int x = backImage->fLoc.x();
1171 const int y = backImage->fLoc.y();
1172 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1173 nullptr, SkMatrix::I());
1174 }
1175
reed@android.com8a1c16f2008-12-17 15:59:43 +00001176 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1177 since if we're being recorded, we don't want to record this (the
1178 recorder will have already recorded the restore).
1179 */
bsalomon49f085d2014-09-05 13:34:00 -07001180 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001181 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001182 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001183 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001184 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001185 layer->fPaint.get(),
1186 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001187 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001188 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001189 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001190 delete layer;
reedb679ca82015-04-07 04:40:48 -07001191 } else {
1192 // we're at the root
reeda499f902015-05-01 09:34:31 -07001193 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001194 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001195 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001196 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001197 }
msarettfbfa2582016-08-12 08:29:08 -07001198
1199 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001200 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001201 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1202 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001203}
1204
reede8f30622016-03-23 18:59:25 -07001205sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001206 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001207 props = &fProps;
1208 }
1209 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001210}
1211
reede8f30622016-03-23 18:59:25 -07001212sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001213 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001214 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001215}
1216
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001217SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001218 return this->onImageInfo();
1219}
1220
1221SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001222 SkBaseDevice* dev = this->getDevice();
1223 if (dev) {
1224 return dev->imageInfo();
1225 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001226 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001227 }
1228}
1229
brianosman898235c2016-04-06 07:38:23 -07001230bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001231 return this->onGetProps(props);
1232}
1233
1234bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001235 SkBaseDevice* dev = this->getDevice();
1236 if (dev) {
1237 if (props) {
1238 *props = fProps;
1239 }
1240 return true;
1241 } else {
1242 return false;
1243 }
1244}
1245
reed6ceeebd2016-03-09 14:26:26 -08001246bool SkCanvas::peekPixels(SkPixmap* pmap) {
1247 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001248}
1249
reed884e97c2015-05-26 11:31:54 -07001250bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001251 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001252 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001253}
1254
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001255void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001256 SkPixmap pmap;
1257 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001258 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001259 }
1260 if (info) {
1261 *info = pmap.info();
1262 }
1263 if (rowBytes) {
1264 *rowBytes = pmap.rowBytes();
1265 }
1266 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001267 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001268 }
reed884e97c2015-05-26 11:31:54 -07001269 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001270}
1271
reed884e97c2015-05-26 11:31:54 -07001272bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001273 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001274 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001275}
1276
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278
Florin Malita53f77bd2017-04-28 13:48:37 -04001279void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1280 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001282 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283 paint = &tmp;
1284 }
reed@google.com4b226022011-01-11 18:32:13 +00001285
Ben Wagner2c312c42018-06-27 14:46:46 -04001286 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001287
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001289 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001290 paint = &looper.paint();
1291 SkImageFilter* filter = paint->getImageFilter();
1292 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001293 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001294 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1295 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001296 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1297 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001298 }
reed@google.com76dd2772012-01-05 21:15:07 +00001299 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001300 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001301 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 }
reeda2217ef2016-07-20 06:04:34 -07001303
reed@google.com4e2b3d32011-04-07 14:18:59 +00001304 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305}
1306
reed32704672015-12-16 08:27:10 -08001307/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001308
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001309void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001310 if (dx || dy) {
1311 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001312 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001313
reedfe69b502016-09-12 06:31:48 -07001314 // Translate shouldn't affect the is-scale-translateness of the matrix.
1315 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001316
Mike Reedc42a1cd2017-02-14 14:25:14 -05001317 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001318
reedfe69b502016-09-12 06:31:48 -07001319 this->didTranslate(dx,dy);
1320 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321}
1322
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001323void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001324 SkMatrix m;
1325 m.setScale(sx, sy);
1326 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001327}
1328
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001329void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001330 SkMatrix m;
1331 m.setRotate(degrees);
1332 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333}
1334
bungeman7438bfc2016-07-12 15:01:19 -07001335void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1336 SkMatrix m;
1337 m.setRotate(degrees, px, py);
1338 this->concat(m);
1339}
1340
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001341void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001342 SkMatrix m;
1343 m.setSkew(sx, sy);
1344 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001345}
1346
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001347void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001348 if (matrix.isIdentity()) {
1349 return;
1350 }
1351
reed2ff1fce2014-12-11 07:07:37 -08001352 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001353 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001354 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001355
Mike Reed7627fa52017-02-08 10:07:53 -05001356 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001357
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001358 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001359}
1360
reed8c30a812016-04-20 16:36:51 -07001361void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001362 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001363 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001364
Mike Reedc42a1cd2017-02-14 14:25:14 -05001365 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001366}
1367
1368void SkCanvas::setMatrix(const SkMatrix& matrix) {
1369 this->checkForDeferredSave();
1370 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001371 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001372}
1373
reed@android.com8a1c16f2008-12-17 15:59:43 +00001374void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001375 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001376}
1377
1378//////////////////////////////////////////////////////////////////////////////
1379
Mike Reedc1f77742016-12-09 09:00:50 -05001380void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001381 if (!rect.isFinite()) {
1382 return;
1383 }
reed2ff1fce2014-12-11 07:07:37 -08001384 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001385 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1386 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001387}
1388
Mike Reedc1f77742016-12-09 09:00:50 -05001389void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001390 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001391
Mike Reed7627fa52017-02-08 10:07:53 -05001392 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001393
reedc64eff52015-11-21 12:39:45 -08001394 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001395 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1396 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001397 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001398}
1399
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001400void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1401 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001402 if (fClipRestrictionRect.isEmpty()) {
1403 // we notify the device, but we *dont* resolve deferred saves (since we're just
1404 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001405 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001406 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001407 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001408 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001409 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001410 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001411 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1412 }
1413}
1414
Mike Reedc1f77742016-12-09 09:00:50 -05001415void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001416 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001417 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001418 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001419 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1420 } else {
1421 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001422 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001423}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001424
Mike Reedc1f77742016-12-09 09:00:50 -05001425void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001426 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001427
Brian Salomona3b45d42016-10-03 11:36:16 -04001428 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001429
Mike Reed7627fa52017-02-08 10:07:53 -05001430 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001431
Mike Reed20800c82017-11-15 16:09:04 -05001432 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1433 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001434 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001435}
1436
Mike Reedc1f77742016-12-09 09:00:50 -05001437void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001438 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001439 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001440
1441 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1442 SkRect r;
1443 if (path.isRect(&r)) {
1444 this->onClipRect(r, op, edgeStyle);
1445 return;
1446 }
1447 SkRRect rrect;
1448 if (path.isOval(&r)) {
1449 rrect.setOval(r);
1450 this->onClipRRect(rrect, op, edgeStyle);
1451 return;
1452 }
1453 if (path.isRRect(&rrect)) {
1454 this->onClipRRect(rrect, op, edgeStyle);
1455 return;
1456 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001457 }
robertphillips39f05382015-11-24 09:30:12 -08001458
1459 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001460}
1461
Mike Reedc1f77742016-12-09 09:00:50 -05001462void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001463 AutoValidateClip avc(this);
1464
Brian Salomona3b45d42016-10-03 11:36:16 -04001465 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001466
Mike Reed7627fa52017-02-08 10:07:53 -05001467 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468
Brian Salomona3b45d42016-10-03 11:36:16 -04001469 const SkPath* rasterClipPath = &path;
1470 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001471 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1472 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001473 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001474}
1475
Mike Reedc1f77742016-12-09 09:00:50 -05001476void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001477 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001478 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001479}
1480
Mike Reedc1f77742016-12-09 09:00:50 -05001481void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001482 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001483
reed@google.com5c3d1472011-02-22 19:12:23 +00001484 AutoValidateClip avc(this);
1485
Mike Reed20800c82017-11-15 16:09:04 -05001486 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001487 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488}
1489
reed@google.com819c9212011-02-23 18:56:55 +00001490#ifdef SK_DEBUG
1491void SkCanvas::validateClip() const {
1492 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001493 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001494 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001495 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001496 return;
1497 }
reed@google.com819c9212011-02-23 18:56:55 +00001498}
1499#endif
1500
Mike Reeda1361362017-03-07 09:37:29 -05001501bool SkCanvas::androidFramework_isClipAA() const {
1502 bool containsAA = false;
1503
1504 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1505
1506 return containsAA;
1507}
1508
1509class RgnAccumulator {
1510 SkRegion* fRgn;
1511public:
1512 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1513 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1514 SkIPoint origin = device->getOrigin();
1515 if (origin.x() | origin.y()) {
1516 rgn->translate(origin.x(), origin.y());
1517 }
1518 fRgn->op(*rgn, SkRegion::kUnion_Op);
1519 }
1520};
1521
1522void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1523 RgnAccumulator accum(rgn);
1524 SkRegion tmp;
1525
1526 rgn->setEmpty();
1527 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001528}
1529
reed@google.com5c3d1472011-02-22 19:12:23 +00001530///////////////////////////////////////////////////////////////////////////////
1531
reed@google.com754de5f2014-02-24 19:38:20 +00001532bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001533 return fMCRec->fRasterClip.isEmpty();
1534
1535 // TODO: should we only use the conservative answer in a recording canvas?
1536#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001537 SkBaseDevice* dev = this->getTopDevice();
1538 // if no device we return true
1539 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001540#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001541}
1542
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001543bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001544 SkBaseDevice* dev = this->getTopDevice();
1545 // if no device we return false
1546 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001547}
1548
msarettfbfa2582016-08-12 08:29:08 -07001549static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1550#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1551 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1552 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1553 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1554 return 0xF != _mm_movemask_ps(mask);
1555#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1556 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1557 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1558 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1559 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1560#else
1561 SkRect devRectAsRect;
1562 SkRect devClipAsRect;
1563 devRect.store(&devRectAsRect.fLeft);
1564 devClip.store(&devClipAsRect.fLeft);
1565 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1566#endif
1567}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001568
msarettfbfa2582016-08-12 08:29:08 -07001569// It's important for this function to not be inlined. Otherwise the compiler will share code
1570// between the fast path and the slow path, resulting in two slow paths.
1571static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1572 const SkMatrix& matrix) {
1573 SkRect deviceRect;
1574 matrix.mapRect(&deviceRect, src);
1575 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1576}
1577
1578bool SkCanvas::quickReject(const SkRect& src) const {
1579#ifdef SK_DEBUG
1580 // Verify that fDeviceClipBounds are set properly.
1581 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001582 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001583 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001584 } else {
msarettfbfa2582016-08-12 08:29:08 -07001585 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001586 }
msarettfbfa2582016-08-12 08:29:08 -07001587
msarett9637ea92016-08-18 14:03:30 -07001588 // Verify that fIsScaleTranslate is set properly.
1589 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001590#endif
1591
msarett9637ea92016-08-18 14:03:30 -07001592 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001593 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1594 }
1595
1596 // We inline the implementation of mapScaleTranslate() for the fast path.
1597 float sx = fMCRec->fMatrix.getScaleX();
1598 float sy = fMCRec->fMatrix.getScaleY();
1599 float tx = fMCRec->fMatrix.getTranslateX();
1600 float ty = fMCRec->fMatrix.getTranslateY();
1601 Sk4f scale(sx, sy, sx, sy);
1602 Sk4f trans(tx, ty, tx, ty);
1603
1604 // Apply matrix.
1605 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1606
1607 // Make sure left < right, top < bottom.
1608 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1609 Sk4f min = Sk4f::Min(ltrb, rblt);
1610 Sk4f max = Sk4f::Max(ltrb, rblt);
1611 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1612 // ARM this sequence generates the fastest (a single instruction).
1613 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1614
1615 // Check if the device rect is NaN or outside the clip.
1616 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001617}
1618
reed@google.com3b3e8952012-08-16 20:53:31 +00001619bool SkCanvas::quickReject(const SkPath& path) const {
1620 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001621}
1622
Mike Klein83c8dd92017-11-28 17:08:45 -05001623SkRect SkCanvas::getLocalClipBounds() const {
1624 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001625 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001626 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001627 }
1628
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001629 SkMatrix inverse;
1630 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001631 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001632 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001633 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001634
Mike Reed42e8c532017-01-23 14:09:13 -05001635 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001636 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001637 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001638
Mike Reedb57b9312018-04-23 12:12:54 -04001639 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001640 inverse.mapRect(&bounds, r);
1641 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001642}
1643
Mike Klein83c8dd92017-11-28 17:08:45 -05001644SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001645 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001646}
1647
reed@android.com8a1c16f2008-12-17 15:59:43 +00001648const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001649 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001650}
1651
Brian Osman11052242016-10-27 14:47:55 -04001652GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001653 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001654 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001655}
1656
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001657GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001658 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001659 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001660}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001661
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001662void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1663 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001664 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001665 if (outer.isEmpty()) {
1666 return;
1667 }
1668 if (inner.isEmpty()) {
1669 this->drawRRect(outer, paint);
1670 return;
1671 }
1672
1673 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001674 // be able to return ...
1675 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001676 //
1677 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001678 if (!outer.getBounds().contains(inner.getBounds())) {
1679 return;
1680 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001681
1682 this->onDrawDRRect(outer, inner, paint);
1683}
1684
reed41af9662015-01-05 07:49:08 -08001685void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001686 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001687 this->onDrawPaint(paint);
1688}
1689
1690void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001691 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001692 // To avoid redundant logic in our culling code and various backends, we always sort rects
1693 // before passing them along.
1694 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001695}
1696
msarettdca352e2016-08-26 06:37:45 -07001697void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001698 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001699 if (region.isEmpty()) {
1700 return;
1701 }
1702
1703 if (region.isRect()) {
1704 return this->drawIRect(region.getBounds(), paint);
1705 }
1706
1707 this->onDrawRegion(region, paint);
1708}
1709
reed41af9662015-01-05 07:49:08 -08001710void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001711 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001712 // To avoid redundant logic in our culling code and various backends, we always sort rects
1713 // before passing them along.
1714 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001715}
1716
1717void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001718 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001719 this->onDrawRRect(rrect, paint);
1720}
1721
1722void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001723 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001724 this->onDrawPoints(mode, count, pts, paint);
1725}
1726
Mike Reede88a1cb2017-03-17 09:50:46 -04001727void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1728 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001729 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001730 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001731 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1732 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001733 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001734}
1735
1736void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001737 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001738 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001739 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1740}
1741
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001742void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1743 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001744 TRACE_EVENT0("skia", TRACE_FUNC);
1745 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001746 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001747 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1748}
1749
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001750void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1751 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001752 TRACE_EVENT0("skia", TRACE_FUNC);
1753 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001754 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001755 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001756}
1757
1758void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001759 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001760 this->onDrawPath(path, paint);
1761}
1762
reeda85d4d02015-05-06 12:56:48 -07001763void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001764 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001765 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001766 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001767}
1768
Mike Reedc4e31092018-01-30 11:15:27 -05001769// Returns true if the rect can be "filled" : non-empty and finite
1770static bool fillable(const SkRect& r) {
1771 SkScalar w = r.width();
1772 SkScalar h = r.height();
1773 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1774}
1775
reede47829b2015-08-06 10:02:53 -07001776void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1777 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001778 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001779 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001780 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001781 return;
1782 }
1783 this->onDrawImageRect(image, &src, dst, paint, constraint);
1784}
reed41af9662015-01-05 07:49:08 -08001785
reed84984ef2015-07-17 07:09:43 -07001786void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1787 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001788 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001789 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001790}
1791
Brian Salomonf08002c2018-10-26 16:15:46 -04001792void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001793 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001794 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001795 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001796}
reede47829b2015-08-06 10:02:53 -07001797
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001798namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001799class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001800public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001801 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1802 if (!origPaint) {
1803 return;
1804 }
1805 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1806 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1807 }
1808 if (origPaint->getMaskFilter()) {
1809 fPaint.writable()->setMaskFilter(nullptr);
1810 }
1811 if (origPaint->isAntiAlias()) {
1812 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001813 }
1814 }
1815
1816 const SkPaint* get() const {
1817 return fPaint;
1818 }
1819
1820private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001821 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001822};
1823} // namespace
1824
reed4c21dc52015-06-25 12:32:03 -07001825void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1826 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001827 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001828 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001829 if (dst.isEmpty()) {
1830 return;
1831 }
msarett552bca92016-08-03 06:53:26 -07001832 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001833 LatticePaint latticePaint(paint);
1834 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001835 } else {
reede47829b2015-08-06 10:02:53 -07001836 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001837 }
reed4c21dc52015-06-25 12:32:03 -07001838}
1839
msarett16882062016-08-16 09:31:08 -07001840void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1841 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001842 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001843 RETURN_ON_NULL(image);
1844 if (dst.isEmpty()) {
1845 return;
1846 }
msarett71df2d72016-09-30 12:41:42 -07001847
1848 SkIRect bounds;
1849 Lattice latticePlusBounds = lattice;
1850 if (!latticePlusBounds.fBounds) {
1851 bounds = SkIRect::MakeWH(image->width(), image->height());
1852 latticePlusBounds.fBounds = &bounds;
1853 }
1854
1855 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001856 LatticePaint latticePaint(paint);
1857 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001858 } else {
1859 this->drawImageRect(image, dst, paint);
1860 }
1861}
1862
Brian Salomon1da5cad2018-11-21 09:21:18 -05001863void SkCanvas::experimental_DrawImageSetV1(const ImageSetEntry imageSet[], int cnt,
1864 SkFilterQuality filterQuality, SkBlendMode mode) {
1865 TRACE_EVENT0("skia", TRACE_FUNC);
1866 RETURN_ON_NULL(imageSet);
1867 RETURN_ON_FALSE(cnt);
1868
Brian Salomond003d222018-11-26 13:25:05 -05001869 this->onDrawImageSet(imageSet, cnt, filterQuality, mode);
Brian Salomon1da5cad2018-11-21 09:21:18 -05001870}
1871
Michael Ludwig75451902019-01-23 11:14:29 -05001872void SkCanvas::experimental_DrawEdgeAARectV1(const SkRect& r, QuadAAFlags edgeAA, SkColor color,
1873 SkBlendMode mode) {
1874 TRACE_EVENT0("skia", TRACE_FUNC);
1875 // To avoid redundant logic in our culling code and various backends, we always sort rects
1876 // before passing them along.
1877 this->onDrawEdgeAARect(r.makeSorted(), edgeAA, color, mode);
1878}
1879
reed41af9662015-01-05 07:49:08 -08001880void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001881 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001882 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001883 return;
1884 }
reed41af9662015-01-05 07:49:08 -08001885 this->onDrawBitmap(bitmap, dx, dy, paint);
1886}
1887
reede47829b2015-08-06 10:02:53 -07001888void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001889 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001890 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001891 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001892 return;
1893 }
reede47829b2015-08-06 10:02:53 -07001894 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001895}
1896
reed84984ef2015-07-17 07:09:43 -07001897void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1898 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001899 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001900}
1901
reede47829b2015-08-06 10:02:53 -07001902void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1903 SrcRectConstraint constraint) {
1904 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1905 constraint);
1906}
reede47829b2015-08-06 10:02:53 -07001907
reed41af9662015-01-05 07:49:08 -08001908void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1909 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001910 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001911 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001912 return;
1913 }
msarett552bca92016-08-03 06:53:26 -07001914 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001915 LatticePaint latticePaint(paint);
1916 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001917 } else {
reeda5517e22015-07-14 10:54:12 -07001918 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001919 }
reed41af9662015-01-05 07:49:08 -08001920}
1921
msarettc573a402016-08-02 08:05:56 -07001922void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1923 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001924 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001925 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001926 return;
1927 }
msarett71df2d72016-09-30 12:41:42 -07001928
1929 SkIRect bounds;
1930 Lattice latticePlusBounds = lattice;
1931 if (!latticePlusBounds.fBounds) {
1932 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1933 latticePlusBounds.fBounds = &bounds;
1934 }
1935
1936 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001937 LatticePaint latticePaint(paint);
1938 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001939 } else {
msarett16882062016-08-16 09:31:08 -07001940 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001941 }
msarettc573a402016-08-02 08:05:56 -07001942}
1943
reed71c3c762015-06-24 10:29:17 -07001944void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001945 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001946 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001947 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001948 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001949 if (count <= 0) {
1950 return;
1951 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001952 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001953 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001954 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001955}
1956
reedf70b5312016-03-04 16:36:20 -08001957void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001958 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001959 if (key) {
1960 this->onDrawAnnotation(rect, key, value);
1961 }
1962}
1963
reede47829b2015-08-06 10:02:53 -07001964void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1965 const SkPaint* paint, SrcRectConstraint constraint) {
1966 if (src) {
1967 this->drawImageRect(image, *src, dst, paint, constraint);
1968 } else {
1969 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1970 dst, paint, constraint);
1971 }
1972}
1973void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1974 const SkPaint* paint, SrcRectConstraint constraint) {
1975 if (src) {
1976 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1977 } else {
1978 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1979 dst, paint, constraint);
1980 }
1981}
1982
Mike Reed4204da22017-05-17 08:53:36 -04001983void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001984 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001985 this->onDrawShadowRec(path, rec);
1986}
1987
1988void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1989 SkPaint paint;
1990 const SkRect& pathBounds = path.getBounds();
1991
Ben Wagner2c312c42018-06-27 14:46:46 -04001992 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001993 while (iter.next()) {
1994 iter.fDevice->drawShadow(path, rec);
1995 }
1996 LOOPER_END
1997}
1998
reed@android.com8a1c16f2008-12-17 15:59:43 +00001999//////////////////////////////////////////////////////////////////////////////
2000// These are the virtual drawing methods
2001//////////////////////////////////////////////////////////////////////////////
2002
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002003void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002004 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002005 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2006 }
2007}
2008
reed41af9662015-01-05 07:49:08 -08002009void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002010 this->internalDrawPaint(paint);
2011}
2012
2013void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002014 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002015
2016 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002017 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002018 }
2019
reed@google.com4e2b3d32011-04-07 14:18:59 +00002020 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002021}
2022
reed41af9662015-01-05 07:49:08 -08002023void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2024 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002025 if ((long)count <= 0) {
2026 return;
2027 }
2028
Mike Reed822128b2017-02-28 16:41:03 -05002029 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002030 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002031 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002032 // special-case 2 points (common for drawing a single line)
2033 if (2 == count) {
2034 r.set(pts[0], pts[1]);
2035 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002036 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002037 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05002038 if (!r.isFinite()) {
2039 return;
2040 }
Mike Reed822128b2017-02-28 16:41:03 -05002041 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002042 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2043 return;
2044 }
2045 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002046 }
reed@google.coma584aed2012-05-16 14:06:02 +00002047
halcanary96fcdcc2015-08-27 07:41:13 -07002048 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002049
Ben Wagner2c312c42018-06-27 14:46:46 -04002050 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002051
reed@android.com8a1c16f2008-12-17 15:59:43 +00002052 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002053 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002054 }
reed@google.com4b226022011-01-11 18:32:13 +00002055
reed@google.com4e2b3d32011-04-07 14:18:59 +00002056 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002057}
2058
reed4a167172016-08-18 17:15:25 -07002059static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2060 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07002061 (intptr_t)paint.getLooper() ) != 0;
2062}
2063
reed41af9662015-01-05 07:49:08 -08002064void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002065 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002066 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002067 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002068 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002069 return;
2070 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002071 }
reed@google.com4b226022011-01-11 18:32:13 +00002072
reed4a167172016-08-18 17:15:25 -07002073 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002074 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002075
reed4a167172016-08-18 17:15:25 -07002076 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002077 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002078 }
2079
2080 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002081 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002082 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002083 SkDrawIter iter(this);
2084 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002085 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002086 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002087 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002088}
2089
Michael Ludwig75451902019-01-23 11:14:29 -05002090void SkCanvas::onDrawEdgeAARect(const SkRect& r, QuadAAFlags edgeAA, SkColor color,
2091 SkBlendMode mode) {
2092 SkASSERT(r.isSorted());
2093
2094 SkPaint paint;
2095 LOOPER_BEGIN(paint, nullptr)
2096
2097 while (iter.next()) {
2098 iter.fDevice->drawEdgeAARect(r, edgeAA, color, mode);
2099 }
2100
2101 LOOPER_END
2102}
2103
msarett44df6512016-08-25 13:54:30 -07002104void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002105 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002106 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002107 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002108 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2109 return;
2110 }
msarett44df6512016-08-25 13:54:30 -07002111 }
2112
Ben Wagner2c312c42018-06-27 14:46:46 -04002113 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002114
2115 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002116 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002117 }
2118
2119 LOOPER_END
2120}
2121
reed41af9662015-01-05 07:49:08 -08002122void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002123 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002124 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002125 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002126 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002127 return;
2128 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002129 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002130
Ben Wagner2c312c42018-06-27 14:46:46 -04002131 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002132
2133 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002134 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002135 }
2136
2137 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002138}
2139
bsalomonac3aa242016-08-19 11:25:19 -07002140void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2141 SkScalar sweepAngle, bool useCenter,
2142 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002143 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002144 if (paint.canComputeFastBounds()) {
2145 SkRect storage;
2146 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002147 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002148 return;
2149 }
bsalomonac3aa242016-08-19 11:25:19 -07002150 }
2151
Ben Wagner2c312c42018-06-27 14:46:46 -04002152 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002153
2154 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002155 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002156 }
2157
2158 LOOPER_END
2159}
2160
reed41af9662015-01-05 07:49:08 -08002161void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002162 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002163 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002164 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2165 return;
2166 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002167 }
2168
2169 if (rrect.isRect()) {
2170 // call the non-virtual version
2171 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002172 return;
2173 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002174 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002175 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2176 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002177 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002178
Ben Wagner2c312c42018-06-27 14:46:46 -04002179 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002180
2181 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002182 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002183 }
2184
2185 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002186}
2187
Mike Reed822128b2017-02-28 16:41:03 -05002188void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002189 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002190 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002191 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2192 return;
2193 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002194 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002195
Ben Wagner2c312c42018-06-27 14:46:46 -04002196 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002197
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002198 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002199 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002200 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002201
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002202 LOOPER_END
2203}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002204
reed41af9662015-01-05 07:49:08 -08002205void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002206 if (!path.isFinite()) {
2207 return;
2208 }
2209
Mike Reed822128b2017-02-28 16:41:03 -05002210 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002211 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002212 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002213 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2214 return;
2215 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002216 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002217
Mike Reed822128b2017-02-28 16:41:03 -05002218 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002219 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002220 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002221 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002222 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002223 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002224
Ben Wagner2c312c42018-06-27 14:46:46 -04002225 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002226
2227 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002228 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002229 }
2230
reed@google.com4e2b3d32011-04-07 14:18:59 +00002231 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002232}
2233
reed262a71b2015-12-05 13:07:27 -08002234bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002235 if (!paint.getImageFilter()) {
2236 return false;
2237 }
2238
2239 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002240 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002241 return false;
2242 }
2243
2244 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2245 // Once we can filter and the filter will return a result larger than itself, we should be
2246 // able to remove this constraint.
2247 // skbug.com/4526
2248 //
2249 SkPoint pt;
2250 ctm.mapXY(x, y, &pt);
2251 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2252 return ir.contains(fMCRec->fRasterClip.getBounds());
2253}
2254
Mike Reedf441cfc2018-04-11 14:50:16 -04002255// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2256// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2257// null.
2258static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2259 if (paintParam) {
2260 *real = *paintParam;
2261 real->setStyle(SkPaint::kFill_Style);
2262 real->setPathEffect(nullptr);
2263 paintParam = real;
2264 }
2265 return paintParam;
2266}
2267
reeda85d4d02015-05-06 12:56:48 -07002268void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002269 SkPaint realPaint;
2270 paint = init_image_paint(&realPaint, paint);
2271
reeda85d4d02015-05-06 12:56:48 -07002272 SkRect bounds = SkRect::MakeXYWH(x, y,
2273 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002274 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002275 SkRect tmp = bounds;
2276 if (paint) {
2277 paint->computeFastBounds(tmp, &tmp);
2278 }
2279 if (this->quickReject(tmp)) {
2280 return;
2281 }
reeda85d4d02015-05-06 12:56:48 -07002282 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002283 // At this point we need a real paint object. If the caller passed null, then we should
2284 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2285 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2286 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002287
reeda2217ef2016-07-20 06:04:34 -07002288 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002289 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2290 *paint);
2291 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002292 special = this->getDevice()->makeSpecial(image);
2293 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002294 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002295 }
2296 }
2297
reed262a71b2015-12-05 13:07:27 -08002298 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2299
reeda85d4d02015-05-06 12:56:48 -07002300 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002301 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002302 if (special) {
2303 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002304 iter.fDevice->ctm().mapXY(x, y, &pt);
2305 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002306 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002307 SkScalarRoundToInt(pt.fY), pnt,
2308 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002309 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002310 iter.fDevice->drawImageRect(
2311 image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt,
2312 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002313 }
reeda85d4d02015-05-06 12:56:48 -07002314 }
halcanary9d524f22016-03-29 09:03:52 -07002315
reeda85d4d02015-05-06 12:56:48 -07002316 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002317}
2318
reed41af9662015-01-05 07:49:08 -08002319void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002320 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002321 SkPaint realPaint;
2322 paint = init_image_paint(&realPaint, paint);
2323
halcanary96fcdcc2015-08-27 07:41:13 -07002324 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002325 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002326 if (paint) {
2327 paint->computeFastBounds(dst, &storage);
2328 }
2329 if (this->quickReject(storage)) {
2330 return;
2331 }
reeda85d4d02015-05-06 12:56:48 -07002332 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002333 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002334
Ben Wagner2c312c42018-06-27 14:46:46 -04002335 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002336
reeda85d4d02015-05-06 12:56:48 -07002337 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002338 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002339 }
halcanary9d524f22016-03-29 09:03:52 -07002340
reeda85d4d02015-05-06 12:56:48 -07002341 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002342}
2343
reed41af9662015-01-05 07:49:08 -08002344void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002345 SkDEBUGCODE(bitmap.validate();)
2346
reed33366972015-10-08 09:22:02 -07002347 if (bitmap.drawsNothing()) {
2348 return;
2349 }
2350
Mike Reedf441cfc2018-04-11 14:50:16 -04002351 SkPaint realPaint;
2352 init_image_paint(&realPaint, paint);
2353 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002354
Mike Reed822128b2017-02-28 16:41:03 -05002355 SkRect bounds;
2356 bitmap.getBounds(&bounds);
2357 bounds.offset(x, y);
2358 bool canFastBounds = paint->canComputeFastBounds();
2359 if (canFastBounds) {
2360 SkRect storage;
2361 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002362 return;
2363 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002364 }
reed@google.com4b226022011-01-11 18:32:13 +00002365
reeda2217ef2016-07-20 06:04:34 -07002366 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002367 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2368 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002369 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002370 special = this->getDevice()->makeSpecial(bitmap);
2371 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002372 drawAsSprite = false;
2373 }
2374 }
2375
Mike Reed822128b2017-02-28 16:41:03 -05002376 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002377
2378 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002379 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002380 if (special) {
reed262a71b2015-12-05 13:07:27 -08002381 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002382 iter.fDevice->ctm().mapXY(x, y, &pt);
2383 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002384 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002385 SkScalarRoundToInt(pt.fY), pnt,
2386 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002387 } else {
Michael Ludwigb7d64b92019-02-11 11:09:15 -05002388 SkRect fullImage = SkRect::MakeWH(bitmap.width(), bitmap.height());
2389 iter.fDevice->drawBitmapRect(bitmap, &fullImage, fullImage.makeOffset(x, y), pnt,
2390 kStrict_SrcRectConstraint);
reed262a71b2015-12-05 13:07:27 -08002391 }
reed33366972015-10-08 09:22:02 -07002392 }
msarettfbfa2582016-08-12 08:29:08 -07002393
reed33366972015-10-08 09:22:02 -07002394 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002395}
2396
reed@google.com9987ec32011-09-07 11:57:52 +00002397// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002398void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002399 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002400 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002401 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002402 return;
2403 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002404
halcanary96fcdcc2015-08-27 07:41:13 -07002405 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002406 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002407 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2408 return;
2409 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002410 }
reed@google.com3d608122011-11-21 15:16:16 +00002411
reed@google.com33535f32012-09-25 15:37:50 +00002412 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002413 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002414 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002415 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002416
Ben Wagner2c312c42018-06-27 14:46:46 -04002417 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002418
reed@google.com33535f32012-09-25 15:37:50 +00002419 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002420 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002421 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002422
reed@google.com33535f32012-09-25 15:37:50 +00002423 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002424}
2425
reed41af9662015-01-05 07:49:08 -08002426void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002427 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002428 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002429 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002430}
2431
reed4c21dc52015-06-25 12:32:03 -07002432void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2433 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002434 SkPaint realPaint;
2435 paint = init_image_paint(&realPaint, paint);
2436
halcanary96fcdcc2015-08-27 07:41:13 -07002437 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002438 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002439 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2440 return;
2441 }
reed@google.com3d608122011-11-21 15:16:16 +00002442 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002443 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002444
Ben Wagner2c312c42018-06-27 14:46:46 -04002445 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002446
reed4c21dc52015-06-25 12:32:03 -07002447 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002448 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002449 }
halcanary9d524f22016-03-29 09:03:52 -07002450
reed4c21dc52015-06-25 12:32:03 -07002451 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002452}
2453
reed41af9662015-01-05 07:49:08 -08002454void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2455 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002456 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002457 SkPaint realPaint;
2458 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002459
halcanary96fcdcc2015-08-27 07:41:13 -07002460 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002461 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002462 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2463 return;
2464 }
reed4c21dc52015-06-25 12:32:03 -07002465 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002466 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002467
Ben Wagner2c312c42018-06-27 14:46:46 -04002468 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002469
reed4c21dc52015-06-25 12:32:03 -07002470 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002471 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002472 }
halcanary9d524f22016-03-29 09:03:52 -07002473
reed4c21dc52015-06-25 12:32:03 -07002474 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002475}
2476
msarett16882062016-08-16 09:31:08 -07002477void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2478 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002479 SkPaint realPaint;
2480 paint = init_image_paint(&realPaint, paint);
2481
msarett16882062016-08-16 09:31:08 -07002482 if (nullptr == paint || paint->canComputeFastBounds()) {
2483 SkRect storage;
2484 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2485 return;
2486 }
2487 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002488 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002489
Ben Wagner2c312c42018-06-27 14:46:46 -04002490 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002491
2492 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002493 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002494 }
2495
2496 LOOPER_END
2497}
2498
Brian Salomond003d222018-11-26 13:25:05 -05002499void SkCanvas::onDrawImageSet(const ImageSetEntry imageSet[], int count,
Brian Salomond7065e72018-10-12 11:42:02 -04002500 SkFilterQuality filterQuality, SkBlendMode mode) {
2501 SkPaint paint;
Brian Salomon23356442018-11-30 15:33:19 -05002502 LOOPER_BEGIN(paint, nullptr)
Brian Salomond7065e72018-10-12 11:42:02 -04002503 while (iter.next()) {
Brian Salomond003d222018-11-26 13:25:05 -05002504 iter.fDevice->drawImageSet(imageSet, count, filterQuality, mode);
Brian Salomond7065e72018-10-12 11:42:02 -04002505 }
2506 LOOPER_END
2507}
2508
msarett16882062016-08-16 09:31:08 -07002509void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2510 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002511 SkPaint realPaint;
2512 paint = init_image_paint(&realPaint, paint);
2513
msarett16882062016-08-16 09:31:08 -07002514 if (nullptr == paint || paint->canComputeFastBounds()) {
2515 SkRect storage;
2516 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2517 return;
2518 }
2519 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002520 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002521
Ben Wagner2c312c42018-06-27 14:46:46 -04002522 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002523
2524 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002525 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002526 }
2527
2528 LOOPER_END
2529}
2530
fmalita00d5c2c2014-08-21 08:53:26 -07002531void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2532 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002533 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002534 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002535 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002536 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002537 SkRect tmp;
2538 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2539 return;
2540 }
2541 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002542 }
2543
fmalita024f9962015-03-03 19:08:17 -08002544 // We cannot filter in the looper as we normally do, because the paint is
2545 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002546 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002547
fmalitaaa1b9122014-08-28 14:32:24 -07002548 while (iter.next()) {
Mike Reed30cf62b2018-12-20 11:18:24 -05002549 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002550 }
2551
fmalitaaa1b9122014-08-28 14:32:24 -07002552 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002553}
2554
Mike Reed358fcad2018-11-23 15:27:51 -05002555// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002556void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002557 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2558 TRACE_EVENT0("skia", TRACE_FUNC);
2559 if (byteLength) {
2560 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002561 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002562 }
2563}
Mike Reed4f81bb72019-01-23 09:23:00 -05002564
fmalita00d5c2c2014-08-21 08:53:26 -07002565void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2566 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002567 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002568 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002569 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002570 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002571}
reed@google.come0d9ce82014-04-23 04:00:17 +00002572
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002573void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002574 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002575 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002576
2577 while (iter.next()) {
2578 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002579 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002580 }
2581
2582 LOOPER_END
2583}
2584
dandovb3c9d1c2014-08-12 08:34:29 -07002585void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002586 const SkPoint texCoords[4], SkBlendMode bmode,
2587 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002588 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002589 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002590 return;
2591 }
mtklein6cfa73a2014-08-13 13:33:49 -07002592
Mike Reedfaba3712016-11-03 14:45:31 -04002593 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002594}
2595
2596void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002597 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002598 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002599 // Since a patch is always within the convex hull of the control points, we discard it when its
2600 // bounding rectangle is completely outside the current clip.
2601 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002602 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002603 if (this->quickReject(bounds)) {
2604 return;
2605 }
mtklein6cfa73a2014-08-13 13:33:49 -07002606
Ben Wagner2c312c42018-06-27 14:46:46 -04002607 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002608
dandovecfff212014-08-04 10:02:00 -07002609 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002610 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002611 }
mtklein6cfa73a2014-08-13 13:33:49 -07002612
dandovecfff212014-08-04 10:02:00 -07002613 LOOPER_END
2614}
2615
reeda8db7282015-07-07 10:22:31 -07002616void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002617#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002618 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002619#endif
reede3b38ce2016-01-08 09:18:44 -08002620 RETURN_ON_NULL(dr);
2621 if (x || y) {
2622 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2623 this->onDrawDrawable(dr, &matrix);
2624 } else {
2625 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002626 }
2627}
2628
reeda8db7282015-07-07 10:22:31 -07002629void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002630#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002631 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002632#endif
reede3b38ce2016-01-08 09:18:44 -08002633 RETURN_ON_NULL(dr);
2634 if (matrix && matrix->isIdentity()) {
2635 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002636 }
reede3b38ce2016-01-08 09:18:44 -08002637 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002638}
2639
2640void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002641 // drawable bounds are no longer reliable (e.g. android displaylist)
2642 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002643 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002644}
2645
reed71c3c762015-06-24 10:29:17 -07002646void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002647 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002648 const SkRect* cull, const SkPaint* paint) {
2649 if (cull && this->quickReject(*cull)) {
2650 return;
2651 }
2652
2653 SkPaint pnt;
2654 if (paint) {
2655 pnt = *paint;
2656 }
halcanary9d524f22016-03-29 09:03:52 -07002657
Ben Wagner2c312c42018-06-27 14:46:46 -04002658 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002659 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002660 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002661 }
2662 LOOPER_END
2663}
2664
reedf70b5312016-03-04 16:36:20 -08002665void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2666 SkASSERT(key);
2667
2668 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002669 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002670 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002671 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002672 }
2673 LOOPER_END
2674}
2675
reed@android.com8a1c16f2008-12-17 15:59:43 +00002676//////////////////////////////////////////////////////////////////////////////
2677// These methods are NOT virtual, and therefore must call back into virtual
2678// methods, rather than actually drawing themselves.
2679//////////////////////////////////////////////////////////////////////////////
2680
reed374772b2016-10-05 17:33:02 -07002681void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002682 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002683 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002684 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002685 this->drawPaint(paint);
2686}
2687
2688void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002689 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002690 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2691}
2692
Mike Reed3661bc92017-02-22 13:21:42 -05002693void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002694 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002695 pts[0].set(x0, y0);
2696 pts[1].set(x1, y1);
2697 this->drawPoints(kLines_PointMode, 2, pts, paint);
2698}
2699
Mike Reed3661bc92017-02-22 13:21:42 -05002700void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002701 if (radius < 0) {
2702 radius = 0;
2703 }
2704
2705 SkRect r;
2706 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002707 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002708}
2709
2710void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2711 const SkPaint& paint) {
2712 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002713 SkRRect rrect;
2714 rrect.setRectXY(r, rx, ry);
2715 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002716 } else {
2717 this->drawRect(r, paint);
2718 }
2719}
2720
reed@android.com8a1c16f2008-12-17 15:59:43 +00002721void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2722 SkScalar sweepAngle, bool useCenter,
2723 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002724 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002725 if (oval.isEmpty() || !sweepAngle) {
2726 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 }
bsalomon21af9ca2016-08-25 12:29:23 -07002728 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002729}
2730
reed@android.comf76bacf2009-05-13 14:00:33 +00002731///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002732#ifdef SK_DISABLE_SKPICTURE
2733void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002734
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002735
2736void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2737 const SkPaint* paint) {}
2738#else
Mike Klein88d90712018-01-27 17:30:04 +00002739/**
2740 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2741 * against the playback cost of recursing into the subpicture to get at its actual ops.
2742 *
2743 * For now we pick a conservatively small value, though measurement (and other heuristics like
2744 * the type of ops contained) may justify changing this value.
2745 */
2746#define kMaxPictureOpsToUnrollInsteadOfRef 1
2747
reedd5fa1a42014-08-09 11:08:05 -07002748void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002749 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002750 RETURN_ON_NULL(picture);
2751
reede3b38ce2016-01-08 09:18:44 -08002752 if (matrix && matrix->isIdentity()) {
2753 matrix = nullptr;
2754 }
Mike Klein88d90712018-01-27 17:30:04 +00002755 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2756 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2757 picture->playback(this);
2758 } else {
2759 this->onDrawPicture(picture, matrix, paint);
2760 }
reedd5fa1a42014-08-09 11:08:05 -07002761}
robertphillips9b14f262014-06-04 05:40:44 -07002762
reedd5fa1a42014-08-09 11:08:05 -07002763void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2764 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002765 if (!paint || paint->canComputeFastBounds()) {
2766 SkRect bounds = picture->cullRect();
2767 if (paint) {
2768 paint->computeFastBounds(bounds, &bounds);
2769 }
2770 if (matrix) {
2771 matrix->mapRect(&bounds);
2772 }
2773 if (this->quickReject(bounds)) {
2774 return;
2775 }
2776 }
2777
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002778 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002779 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002780}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002781#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782
reed@android.com8a1c16f2008-12-17 15:59:43 +00002783///////////////////////////////////////////////////////////////////////////////
2784///////////////////////////////////////////////////////////////////////////////
2785
reed3aafe112016-08-18 12:45:34 -07002786SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002787 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002788
2789 SkASSERT(canvas);
2790
reed3aafe112016-08-18 12:45:34 -07002791 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002792 fDone = !fImpl->next();
2793}
2794
2795SkCanvas::LayerIter::~LayerIter() {
2796 fImpl->~SkDrawIter();
2797}
2798
2799void SkCanvas::LayerIter::next() {
2800 fDone = !fImpl->next();
2801}
2802
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002803SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002804 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002805}
2806
2807const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002808 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809}
2810
2811const SkPaint& SkCanvas::LayerIter::paint() const {
2812 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002813 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814 paint = &fDefaultPaint;
2815 }
2816 return *paint;
2817}
2818
Mike Reedca37f322018-03-08 13:22:16 -05002819SkIRect SkCanvas::LayerIter::clipBounds() const {
2820 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002821}
2822
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2824int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002825
2826///////////////////////////////////////////////////////////////////////////////
2827
Mike Reed5df49342016-11-12 08:06:55 -06002828std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002829 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002830 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002831 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002832 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002833
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002834 SkBitmap bitmap;
2835 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002836 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002837 }
Mike Reed12f77342017-11-08 11:19:52 -05002838
2839 return props ?
2840 skstd::make_unique<SkCanvas>(bitmap, *props) :
2841 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002842}
reedd5fa1a42014-08-09 11:08:05 -07002843
2844///////////////////////////////////////////////////////////////////////////////
2845
Florin Malitaee424ac2016-12-01 12:47:59 -05002846SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002847 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002848
Florin Malita439ace92016-12-02 12:05:41 -05002849SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002850 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002851
Herb Derbyefe39bc2018-05-01 17:06:20 -04002852SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002853 : INHERITED(device) {}
2854
Florin Malitaee424ac2016-12-01 12:47:59 -05002855SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2856 (void)this->INHERITED::getSaveLayerStrategy(rec);
2857 return kNoLayer_SaveLayerStrategy;
2858}
2859
Mike Reed148b7fd2018-12-18 17:38:18 -05002860bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2861 return false;
2862}
2863
Florin Malitaee424ac2016-12-01 12:47:59 -05002864///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002865
reed73603f32016-09-20 08:42:38 -07002866static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2867static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2868static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2869static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2870static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2871static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002872
2873///////////////////////////////////////////////////////////////////////////////////////////////////
2874
2875SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2876 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002877 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002878 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2879 SkIPoint origin = dev->getOrigin();
2880 SkMatrix ctm = this->getTotalMatrix();
2881 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2882
2883 SkIRect clip = fMCRec->fRasterClip.getBounds();
2884 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002885 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002886 clip.setEmpty();
2887 }
2888
2889 fAllocator->updateHandle(handle, ctm, clip);
2890 return handle;
2891 }
2892 return nullptr;
2893}
2894
2895static bool install(SkBitmap* bm, const SkImageInfo& info,
2896 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002897 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002898}
2899
2900SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2901 SkBitmap* bm) {
2902 SkRasterHandleAllocator::Rec rec;
2903 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2904 return nullptr;
2905 }
2906 return rec.fHandle;
2907}
2908
2909std::unique_ptr<SkCanvas>
2910SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2911 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04002912 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05002913 return nullptr;
2914 }
2915
2916 SkBitmap bm;
2917 Handle hndl;
2918
2919 if (rec) {
2920 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2921 } else {
2922 hndl = alloc->allocBitmap(info, &bm);
2923 }
2924 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2925}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002926
2927///////////////////////////////////////////////////////////////////////////////////////////////////
2928
2929