blob: 26e2ffaf6758f8ce8f47151253e5cb93aaf130c6 [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 "SkGlyphCache.h"
19#include "SkGlyphRun.h"
piotaixrb5fae932014-09-24 13:03:30 -070020#include "SkImage.h"
senorblanco900c3672016-04-27 11:31:23 -070021#include "SkImageFilter.h"
22#include "SkImageFilterCache.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040023#include "SkImage_Base.h"
msarettc573a402016-08-02 08:05:56 -070024#include "SkLatticeIter.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040025#include "SkMSAN.h"
Mike Reed5df49342016-11-12 08:06:55 -060026#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080027#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000028#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050029#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070030#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070031#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070032#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040033#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000034#include "SkPicture.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040035#include "SkRRect.h"
reed@google.com00177082011-10-12 14:34:30 +000036#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050037#include "SkRasterHandleAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080038#include "SkSpecialImage.h"
Herb Derby41f4f312018-06-06 17:45:53 +000039#include "SkStrikeCache.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040040#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000041#include "SkSurface_Base.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040042#include "SkTLazy.h"
fmalita7ba7aa72014-08-29 09:46:36 -070043#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000044#include "SkTextFormatParams.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040045#include "SkTo.h"
danakj8f757f52014-11-04 11:48:43 -080046#include "SkTraceEvent.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040047#include "SkVertices.h"
48
bungemand3ebb482015-08-05 13:57:49 -070049#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000050
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080052#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050053#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000054#endif
55
reede3b38ce2016-01-08 09:18:44 -080056#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050057#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080058
Mike Reed139e5e02017-03-08 11:29:33 -050059///////////////////////////////////////////////////////////////////////////////////////////////////
60
reedc83a2972015-07-16 07:40:45 -070061/*
62 * Return true if the drawing this rect would hit every pixels in the canvas.
63 *
64 * Returns false if
65 * - rect does not contain the canvas' bounds
66 * - paint is not fill
67 * - paint would blur or otherwise change the coverage of the rect
68 */
69bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
70 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070071 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
72 (int)kNone_ShaderOverrideOpacity,
73 "need_matching_enums0");
74 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
75 (int)kOpaque_ShaderOverrideOpacity,
76 "need_matching_enums1");
77 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
78 (int)kNotOpaque_ShaderOverrideOpacity,
79 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070080
81 const SkISize size = this->getBaseLayerSize();
82 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050083
84 // if we're clipped at all, we can't overwrite the entire surface
85 {
86 SkBaseDevice* base = this->getDevice();
87 SkBaseDevice* top = this->getTopDevice();
88 if (base != top) {
89 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
90 }
91 if (!base->clipIsWideOpen()) {
92 return false;
93 }
reedc83a2972015-07-16 07:40:45 -070094 }
95
96 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070097 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070098 return false; // conservative
99 }
halcanaryc5769b22016-08-10 07:13:21 -0700100
101 SkRect devRect;
102 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
103 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700104 return false;
105 }
106 }
107
108 if (paint) {
109 SkPaint::Style paintStyle = paint->getStyle();
110 if (!(paintStyle == SkPaint::kFill_Style ||
111 paintStyle == SkPaint::kStrokeAndFill_Style)) {
112 return false;
113 }
114 if (paint->getMaskFilter() || paint->getLooper()
115 || paint->getPathEffect() || paint->getImageFilter()) {
116 return false; // conservative
117 }
118 }
119 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
120}
121
122///////////////////////////////////////////////////////////////////////////////////////////////////
123
reed@google.comda17f752012-08-16 18:27:05 +0000124// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125//#define SK_TRACE_SAVERESTORE
126
127#ifdef SK_TRACE_SAVERESTORE
128 static int gLayerCounter;
129 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
130 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
131
132 static int gRecCounter;
133 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
134 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
135
136 static int gCanvasCounter;
137 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
138 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
139#else
140 #define inc_layer()
141 #define dec_layer()
142 #define inc_rec()
143 #define dec_rec()
144 #define inc_canvas()
145 #define dec_canvas()
146#endif
147
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000148typedef SkTLazy<SkPaint> SkLazyPaint;
149
reedc83a2972015-07-16 07:40:45 -0700150void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000151 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700152 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
153 ? SkSurface::kDiscard_ContentChangeMode
154 : SkSurface::kRetain_ContentChangeMode);
155 }
156}
157
158void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
159 ShaderOverrideOpacity overrideOpacity) {
160 if (fSurfaceBase) {
161 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
162 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
163 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
164 // and therefore we don't care which mode we're in.
165 //
166 if (fSurfaceBase->outstandingImageSnapshot()) {
167 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
168 mode = SkSurface::kDiscard_ContentChangeMode;
169 }
170 }
171 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000172 }
173}
174
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000177/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 The clip/matrix/proc are fields that reflect the top of the save/restore
179 stack. Whenever the canvas changes, it marks a dirty flag, and then before
180 these are used (assuming we're not on a layer) we rebuild these cache
181 values: they reflect the top of the save stack, but translated and clipped
182 by the device's XY offset and bitmap-bounds.
183*/
184struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400185 DeviceCM* fNext;
186 sk_sp<SkBaseDevice> fDevice;
187 SkRasterClip fClip;
188 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
189 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400190 sk_sp<SkImage> fClipImage;
191 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192
Florin Malita53f77bd2017-04-28 13:48:37 -0400193 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000194 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700195 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400196 , fDevice(std::move(device))
197 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700198 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000199 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400200 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400201 {}
reed@google.com4b226022011-01-11 18:32:13 +0000202
mtkleinfeaadee2015-04-08 11:25:48 -0700203 void reset(const SkIRect& bounds) {
204 SkASSERT(!fPaint);
205 SkASSERT(!fNext);
206 SkASSERT(fDevice);
207 fClip.setRect(bounds);
208 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209};
210
Mike Reed148b7fd2018-12-18 17:38:18 -0500211namespace {
212// Encapsulate state needed to restore from saveBehind()
213struct BackImage {
214 sk_sp<SkSpecialImage> fImage;
215 SkIPoint fLoc;
216};
217}
218
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219/* This is the record we keep for each save/restore level in the stack.
220 Since a level optionally copies the matrix and/or stack, we have pointers
221 for these fields. If the value is copied for this level, the copy is
222 stored in the ...Storage field, and the pointer points to that. If the
223 value is not copied for this level, we ignore ...Storage, and just point
224 at the corresponding value in the previous level in the stack.
225*/
226class SkCanvas::MCRec {
227public:
Mike Reed148b7fd2018-12-18 17:38:18 -0500228 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229 /* If there are any layers in the stack, this points to the top-most
230 one that is at or below this level in the stack (so we know what
231 bitmap/device to draw into from this level. This value is NOT
232 reference counted, since the real owner is either our fLayer field,
233 or a previous one in a lower level.)
234 */
Mike Reed148b7fd2018-12-18 17:38:18 -0500235 DeviceCM* fTopLayer;
236 std::unique_ptr<BackImage> fBackImage;
237 SkConservativeClip fRasterClip;
238 SkMatrix fMatrix;
239 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240
Mike Reeda1361362017-03-07 09:37:29 -0500241 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700242 fLayer = nullptr;
243 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800244 fMatrix.reset();
245 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700246
reedd9544982014-09-09 18:46:22 -0700247 // don't bother initializing fNext
248 inc_rec();
249 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400250 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700251 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700252 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800253 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700254
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 // don't bother initializing fNext
256 inc_rec();
257 }
258 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700259 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260 dec_rec();
261 }
mtkleinfeaadee2015-04-08 11:25:48 -0700262
263 void reset(const SkIRect& bounds) {
264 SkASSERT(fLayer);
265 SkASSERT(fDeferredSaveCount == 0);
266
267 fMatrix.reset();
268 fRasterClip.setRect(bounds);
269 fLayer->reset(bounds);
270 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271};
272
Mike Reeda1361362017-03-07 09:37:29 -0500273class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274public:
Mike Reeda1361362017-03-07 09:37:29 -0500275 SkDrawIter(SkCanvas* canvas)
276 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
277 {}
reed@google.com4b226022011-01-11 18:32:13 +0000278
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000280 const DeviceCM* rec = fCurrLayer;
281 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400282 fDevice = rec->fDevice.get();
283 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700285 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000286 return true;
287 }
288 return false;
289 }
reed@google.com4b226022011-01-11 18:32:13 +0000290
reed@google.com6f8f2922011-03-04 22:27:10 +0000291 int getX() const { return fDevice->getOrigin().x(); }
292 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000294
Mike Reed99330ba2017-02-22 11:01:08 -0500295 SkBaseDevice* fDevice;
296
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298 const DeviceCM* fCurrLayer;
299 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300};
301
Florin Malita713b8ef2017-04-28 10:57:24 -0400302#define FOR_EACH_TOP_DEVICE( code ) \
303 do { \
304 DeviceCM* layer = fMCRec->fTopLayer; \
305 while (layer) { \
306 SkBaseDevice* device = layer->fDevice.get(); \
307 if (device) { \
308 code; \
309 } \
310 layer = layer->fNext; \
311 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500312 } while (0)
313
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314/////////////////////////////////////////////////////////////////////////////
315
reeddbc3cef2015-04-29 12:18:57 -0700316static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
317 return lazy->isValid() ? lazy->get() : lazy->set(orig);
318}
319
320/**
321 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700322 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700323 */
reedd053ce92016-03-22 10:17:23 -0700324static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700325 SkImageFilter* imgf = paint.getImageFilter();
326 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700327 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700328 }
329
reedd053ce92016-03-22 10:17:23 -0700330 SkColorFilter* imgCFPtr;
331 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700332 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700333 }
reedd053ce92016-03-22 10:17:23 -0700334 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700335
336 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700337 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700338 // there is no existing paint colorfilter, so we can just return the imagefilter's
339 return imgCF;
340 }
341
342 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
343 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500344 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700345}
346
senorblanco87e066e2015-10-28 11:23:36 -0700347/**
348 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
349 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
350 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
351 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
352 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
353 * conservative "effective" bounds based on the settings in the paint... with one exception. This
354 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
355 * deliberately ignored.
356 */
357static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
358 const SkRect& rawBounds,
359 SkRect* storage) {
360 SkPaint tmpUnfiltered(paint);
361 tmpUnfiltered.setImageFilter(nullptr);
362 if (tmpUnfiltered.canComputeFastBounds()) {
363 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
364 } else {
365 return rawBounds;
366 }
367}
368
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369class AutoDrawLooper {
370public:
senorblanco87e066e2015-10-28 11:23:36 -0700371 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
372 // paint. It's used to determine the size of the offscreen layer for filters.
373 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700374 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700375 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000376 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700377 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000378 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700379 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000380 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381
reedd053ce92016-03-22 10:17:23 -0700382 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700383 if (simplifiedCF) {
384 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700385 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700386 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700387 fPaint = paint;
388 }
389
390 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700391 /**
392 * We implement ImageFilters for a given draw by creating a layer, then applying the
393 * imagefilter to the pixels of that layer (its backing surface/image), and then
394 * we call restore() to xfer that layer to the main canvas.
395 *
396 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
397 * 2. Generate the src pixels:
398 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
399 * return (fPaint). We then draw the primitive (using srcover) into a cleared
400 * buffer/surface.
401 * 3. Restore the layer created in #1
402 * The imagefilter is passed the buffer/surface from the layer (now filled with the
403 * src pixels of the primitive). It returns a new "filtered" buffer, which we
404 * draw onto the previous layer using the xfermode from the original paint.
405 */
reed@google.com8926b162012-03-23 15:36:36 +0000406 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500407 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700408 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700409 SkRect storage;
410 if (rawBounds) {
411 // Make rawBounds include all paint outsets except for those due to image filters.
412 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
413 }
reedbfd5f172016-01-07 11:28:08 -0800414 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700415 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700416 fTempLayerForImageFilter = true;
417 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000418 }
419
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000420 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500421 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000422 fIsSimple = false;
423 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700424 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000425 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400426 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000427 }
428 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000429
reed@android.com8a1c16f2008-12-17 15:59:43 +0000430 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700431 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000432 fCanvas->internalRestore();
433 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000434 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000436
reed@google.com4e2b3d32011-04-07 14:18:59 +0000437 const SkPaint& paint() const {
438 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400439 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000440 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000442
Ben Wagner2c312c42018-06-27 14:46:46 -0400443 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000444 if (fDone) {
445 return false;
446 } else if (fIsSimple) {
447 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000448 return !fPaint->nothingToDraw();
449 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400450 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000451 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000452 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000453
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500455 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700456 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000457 SkCanvas* fCanvas;
458 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000459 const SkPaint* fPaint;
460 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700461 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000462 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000463 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000464 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400465 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000466
Ben Wagner2c312c42018-06-27 14:46:46 -0400467 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000468};
469
Ben Wagner2c312c42018-06-27 14:46:46 -0400470bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700471 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000472 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400473 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000474
reeddbc3cef2015-04-29 12:18:57 -0700475 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
476 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400477 // never want our downstream clients (i.e. devices) to see loopers
478 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000479
reed5c476fb2015-04-20 08:04:21 -0700480 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700481 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700482 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000483 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000484
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000485 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000486 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000487 return false;
488 }
reed@google.com129ec222012-05-15 13:24:09 +0000489 fPaint = paint;
490
491 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400492 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000493 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000494 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000495 return true;
496}
497
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498////////// macros to place around the internal draw calls //////////////////
499
reed3aafe112016-08-18 12:45:34 -0700500#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
501 this->predrawNotify(); \
502 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400503 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800504 SkDrawIter iter(this);
505
506
Ben Wagner2c312c42018-06-27 14:46:46 -0400507#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000508 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700509 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400510 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000511 SkDrawIter iter(this);
512
Ben Wagner2c312c42018-06-27 14:46:46 -0400513#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000514 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700515 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400516 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000518
Ben Wagner2c312c42018-06-27 14:46:46 -0400519#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700520 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700521 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400522 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700523 SkDrawIter iter(this);
524
reed@google.com4e2b3d32011-04-07 14:18:59 +0000525#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526
527////////////////////////////////////////////////////////////////////////////
528
msarettfbfa2582016-08-12 08:29:08 -0700529static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
530 if (bounds.isEmpty()) {
531 return SkRect::MakeEmpty();
532 }
533
534 // Expand bounds out by 1 in case we are anti-aliasing. We store the
535 // bounds as floats to enable a faster quick reject implementation.
536 SkRect dst;
537 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
538 return dst;
539}
540
mtkleinfeaadee2015-04-08 11:25:48 -0700541void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
542 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700543 fMCRec->reset(bounds);
544
545 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500546 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400547 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700548 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700549 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700550}
551
Hal Canary363a3f82018-10-04 11:04:48 -0400552void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000553 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800554 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700555 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000556
557 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500558 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500559 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700560 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000561
reeda499f902015-05-01 09:34:31 -0700562 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
563 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400564 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700565
reed@android.com8a1c16f2008-12-17 15:59:43 +0000566 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000567
halcanary96fcdcc2015-08-27 07:41:13 -0700568 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000569
reedf92c8662014-08-18 08:02:43 -0700570 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700571 // The root device and the canvas should always have the same pixel geometry
572 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800573 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700574 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500575
Mike Reedc42a1cd2017-02-14 14:25:14 -0500576 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700577 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400578
Herb Derby59d997a2018-06-07 12:44:09 -0400579 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000580}
581
reed@google.comcde92112011-07-06 20:00:52 +0000582SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000583 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700584 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000585{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000586 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000587
Hal Canary363a3f82018-10-04 11:04:48 -0400588 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000589}
590
reed96a857e2015-01-25 10:33:58 -0800591SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000592 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800593 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000594{
595 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400596 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400597 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700598}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000599
Hal Canary363a3f82018-10-04 11:04:48 -0400600SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700601 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700602 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700603{
604 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700605
Mike Reed566e53c2017-03-10 10:49:45 -0500606 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400607 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700608}
609
Herb Derbyefe39bc2018-05-01 17:06:20 -0400610SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000611 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700612 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000613{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700615
Hal Canary363a3f82018-10-04 11:04:48 -0400616 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700617}
618
reed4a8126e2014-09-22 07:29:03 -0700619SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700620 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700621 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700622{
623 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700624
Mike Reed910ca0f2018-04-25 13:04:05 -0400625 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400626 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700627}
reed29c857d2014-09-21 10:25:07 -0700628
Mike Reed356f7c22017-01-10 11:58:39 -0500629SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
630 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700631 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
632 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500633 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700634{
635 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700636
Mike Reed910ca0f2018-04-25 13:04:05 -0400637 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400638 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000639}
640
Mike Reed356f7c22017-01-10 11:58:39 -0500641SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
642
Matt Sarett31f99ce2017-04-11 08:46:01 -0400643#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
644SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
645 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
646 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
647 , fAllocator(nullptr)
648{
649 inc_canvas();
650
651 SkBitmap tmp(bitmap);
652 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400653 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400654 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400655}
656#endif
657
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658SkCanvas::~SkCanvas() {
659 // free up the contents of our deque
660 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000661
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662 this->internalRestore(); // restore the last, since we're going away
663
halcanary385fe4d2015-08-26 13:07:48 -0700664 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000665
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666 dec_canvas();
667}
668
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000669SkMetaData& SkCanvas::getMetaData() {
670 // metadata users are rare, so we lazily allocate it. If that changes we
671 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700672 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000673 fMetaData = new SkMetaData;
674 }
675 return *fMetaData;
676}
677
reed@android.com8a1c16f2008-12-17 15:59:43 +0000678///////////////////////////////////////////////////////////////////////////////
679
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000680void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700681 this->onFlush();
682}
683
684void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000685 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000686 if (device) {
687 device->flush();
688 }
689}
690
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000691SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000692 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000693 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
694}
695
senorblancoafc7cce2016-02-02 18:44:15 -0800696SkIRect SkCanvas::getTopLayerBounds() const {
697 SkBaseDevice* d = this->getTopDevice();
698 if (!d) {
699 return SkIRect::MakeEmpty();
700 }
701 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
702}
703
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000704SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000705 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000706 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000707 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400708 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000709}
710
Florin Malita0ed3b642017-01-13 16:56:38 +0000711SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400712 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000713}
714
Mike Reed353196f2017-07-21 11:01:18 -0400715bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000716 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400717 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000718}
719
Mike Reed353196f2017-07-21 11:01:18 -0400720bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
721 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400722}
723
724bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
725 SkPixmap pm;
726 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
727}
728
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000729bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400730 SkPixmap pm;
731 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700732 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000733 }
734 return false;
735}
736
Matt Sarett03dd6d52017-01-23 12:15:09 -0500737bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000738 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000739 SkBaseDevice* device = this->getDevice();
740 if (!device) {
741 return false;
742 }
743
Matt Sarett03dd6d52017-01-23 12:15:09 -0500744 // This check gives us an early out and prevents generation ID churn on the surface.
745 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
746 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
747 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
748 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000749 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000750
Matt Sarett03dd6d52017-01-23 12:15:09 -0500751 // Tell our owning surface to bump its generation ID.
752 const bool completeOverwrite =
753 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700754 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700755
Matt Sarett03dd6d52017-01-23 12:15:09 -0500756 // This can still fail, most notably in the case of a invalid color type or alpha type
757 // conversion. We could pull those checks into this function and avoid the unnecessary
758 // generation ID bump. But then we would be performing those checks twice, since they
759 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400760 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000761}
reed@google.com51df9e32010-12-23 19:29:18 +0000762
reed@android.com8a1c16f2008-12-17 15:59:43 +0000763//////////////////////////////////////////////////////////////////////////////
764
reed2ff1fce2014-12-11 07:07:37 -0800765void SkCanvas::checkForDeferredSave() {
766 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800767 this->doSave();
768 }
769}
770
reedf0090cb2014-11-26 08:55:51 -0800771int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800772#ifdef SK_DEBUG
773 int count = 0;
774 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
775 for (;;) {
776 const MCRec* rec = (const MCRec*)iter.next();
777 if (!rec) {
778 break;
779 }
780 count += 1 + rec->fDeferredSaveCount;
781 }
782 SkASSERT(count == fSaveCount);
783#endif
784 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800785}
786
787int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800788 fSaveCount += 1;
789 fMCRec->fDeferredSaveCount += 1;
790 return this->getSaveCount() - 1; // return our prev value
791}
792
793void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800794 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700795
796 SkASSERT(fMCRec->fDeferredSaveCount > 0);
797 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800798 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800799}
800
801void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800802 if (fMCRec->fDeferredSaveCount > 0) {
803 SkASSERT(fSaveCount > 1);
804 fSaveCount -= 1;
805 fMCRec->fDeferredSaveCount -= 1;
806 } else {
807 // check for underflow
808 if (fMCStack.count() > 1) {
809 this->willRestore();
810 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700811 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800812 this->internalRestore();
813 this->didRestore();
814 }
reedf0090cb2014-11-26 08:55:51 -0800815 }
816}
817
818void SkCanvas::restoreToCount(int count) {
819 // sanity check
820 if (count < 1) {
821 count = 1;
822 }
mtkleinf0f14112014-12-12 08:46:25 -0800823
reedf0090cb2014-11-26 08:55:51 -0800824 int n = this->getSaveCount() - count;
825 for (int i = 0; i < n; ++i) {
826 this->restore();
827 }
828}
829
reed2ff1fce2014-12-11 07:07:37 -0800830void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700832 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000833 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000834
Mike Reedc42a1cd2017-02-14 14:25:14 -0500835 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836}
837
reed4960eee2015-12-18 07:09:18 -0800838bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400839 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000840}
841
reed4960eee2015-12-18 07:09:18 -0800842bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700843 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500844 SkIRect clipBounds = this->getDeviceClipBounds();
845 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000846 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000847 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000848
reed96e657d2015-03-10 17:30:07 -0700849 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
850
Robert Phillips12078432018-05-17 11:17:39 -0400851 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
852 // If the image filter DAG affects transparent black then we will need to render
853 // out to the clip bounds
854 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000855 }
Robert Phillips12078432018-05-17 11:17:39 -0400856
857 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700858 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000859 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700860 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400861 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000862 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400863 inputSaveLayerBounds = clipBounds;
864 }
865
866 if (imageFilter) {
867 // expand the clip bounds by the image filter DAG to include extra content that might
868 // be required by the image filters.
869 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
870 SkImageFilter::kReverse_MapDirection,
871 &inputSaveLayerBounds);
872 }
873
874 SkIRect clippedSaveLayerBounds;
875 if (bounds) {
876 // For better or for worse, user bounds currently act as a hard clip on the layer's
877 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
878 clippedSaveLayerBounds = inputSaveLayerBounds;
879 } else {
880 // If there are no user bounds, we don't want to artificially restrict the resulting
881 // layer bounds, so allow the expanded clip bounds free reign.
882 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000883 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800884
885 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400886 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800887 if (BoundsAffectsClip(saveLayerFlags)) {
888 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
889 fMCRec->fRasterClip.setEmpty();
890 fDeviceClipBounds.setEmpty();
891 }
892 return false;
893 }
Robert Phillips12078432018-05-17 11:17:39 -0400894 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000895
reed4960eee2015-12-18 07:09:18 -0800896 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700897 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400898 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
899 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000900 }
901
902 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400903 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000904 }
Robert Phillips12078432018-05-17 11:17:39 -0400905
junov@chromium.orga907ac32012-02-24 21:54:07 +0000906 return true;
907}
908
reed4960eee2015-12-18 07:09:18 -0800909int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
910 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000911}
912
Cary Clarke041e312018-03-06 13:00:52 -0500913int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700914 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400915 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
916 // no need for the layer (or any of the draws until the matching restore()
917 this->save();
918 this->clipRect({0,0,0,0});
919 } else {
920 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
921 fSaveCount += 1;
922 this->internalSaveLayer(rec, strategy);
923 }
reed4960eee2015-12-18 07:09:18 -0800924 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800925}
926
Mike Reed148b7fd2018-12-18 17:38:18 -0500927int SkCanvas::only_axis_aligned_saveBehind(const SkRect* bounds) {
928 if (bounds && !this->getLocalClipBounds().intersects(*bounds)) {
929 // Assuming clips never expand, if the request bounds is outside of the current clip
930 // there is no need to copy/restore the area, so just devolve back to a regular save.
931 this->save();
932 } else {
933 bool doTheWork = this->onDoSaveBehind(bounds);
934 fSaveCount += 1;
935 this->internalSave();
936 if (doTheWork) {
937 this->internalSaveBehind(bounds);
938 }
939 }
940 return this->getSaveCount() - 1;
941}
942
reeda2217ef2016-07-20 06:04:34 -0700943void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500944 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500945 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700946 SkDraw draw;
947 SkRasterClip rc;
948 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
949 if (!dst->accessPixels(&draw.fDst)) {
950 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800951 }
reeda2217ef2016-07-20 06:04:34 -0700952 draw.fMatrix = &SkMatrix::I();
953 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800954
955 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500956 if (filter) {
957 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
958 }
reeda2217ef2016-07-20 06:04:34 -0700959
Mike Reedc42a1cd2017-02-14 14:25:14 -0500960 int x = src->getOrigin().x() - dstOrigin.x();
961 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700962 auto special = src->snapSpecial();
963 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400964 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700965 }
robertphillips7354a4b2015-12-16 05:08:27 -0800966}
reed70ee31b2015-12-10 13:44:45 -0800967
Mike Kleine083f7c2018-02-07 12:54:27 -0500968static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500969 // Need to force L32 for now if we have an image filter.
970 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
971 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500972 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800973 }
Mike Klein649fb732018-02-26 15:09:16 -0500974
975 SkColorType ct = prev.colorType();
976 if (prev.bytesPerPixel() <= 4) {
977 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
978 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
979 ct = kN32_SkColorType;
980 }
981 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800982}
983
reed4960eee2015-12-18 07:09:18 -0800984void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700985 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800986 const SkRect* bounds = rec.fBounds;
987 const SkPaint* paint = rec.fPaint;
988 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
989
reed8c30a812016-04-20 16:36:51 -0700990 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400991 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700992 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400993 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700994 SkMatrix remainder;
995 SkSize scale;
996 /*
997 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
998 * but they do handle scaling. To accommodate this, we do the following:
999 *
1000 * 1. Stash off the current CTM
1001 * 2. Decompose the CTM into SCALE and REMAINDER
1002 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1003 * contains the REMAINDER
1004 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1005 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1006 * of the original imagefilter, and draw that (via drawSprite)
1007 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1008 *
1009 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1010 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1011 */
reed96a04f32016-04-25 09:25:15 -07001012 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001013 stashedMatrix.decomposeScale(&scale, &remainder))
1014 {
1015 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001016 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001017 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1018 SkPaint* p = lazyP.set(*paint);
1019 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1020 SkFilterQuality::kLow_SkFilterQuality,
1021 sk_ref_sp(imageFilter)));
1022 imageFilter = p->getImageFilter();
1023 paint = p;
1024 }
reed8c30a812016-04-20 16:36:51 -07001025
junov@chromium.orga907ac32012-02-24 21:54:07 +00001026 // do this before we create the layer. We don't call the public save() since
1027 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001028 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001029
junov@chromium.orga907ac32012-02-24 21:54:07 +00001030 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001031 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001032 if (modifiedRec) {
1033 // In this case there will be no layer in which to stash the matrix so we need to
1034 // revert the prior MCRec to its earlier state.
1035 modifiedRec->fMatrix = stashedMatrix;
1036 }
reed2ff1fce2014-12-11 07:07:37 -08001037 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001038 }
1039
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001040 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1041 // the clipRectBounds() call above?
1042 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001043 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001044 }
1045
reed8dc0ccb2015-03-20 06:32:52 -07001046 SkPixelGeometry geo = fProps.pixelGeometry();
1047 if (paint) {
reed76033be2015-03-14 10:54:31 -07001048 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001049 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001050 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001051 }
1052 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001053
robertphillips5139e502016-07-19 05:10:40 -07001054 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001055 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001056 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001057 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001058 }
reedb2db8982014-11-13 12:41:02 -08001059
Mike Kleine083f7c2018-02-07 12:54:27 -05001060 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001061
Hal Canary704cd322016-11-07 14:13:52 -05001062 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001063 {
Florin Malita07e4adf2019-01-07 16:34:18 -05001064 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType();
reeddaa57bf2015-05-15 10:39:17 -07001065 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001066 const bool trackCoverage =
1067 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001068 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001069 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001070 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001071 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001072 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1073 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001074 return;
reed61f501f2015-04-29 08:34:00 -07001075 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001076 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001077 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001078
Mike Reedb43a3e02017-02-11 10:18:58 -05001079 // only have a "next" if this new layer doesn't affect the clip (rare)
1080 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001081 fMCRec->fLayer = layer;
1082 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001083
Mike Reedc61abee2017-02-28 17:45:27 -05001084 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001085 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001086 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001087 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001088
Mike Reedc42a1cd2017-02-14 14:25:14 -05001089 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1090
1091 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1092 if (layer->fNext) {
1093 // need to punch a hole in the previous device, so we don't draw there, given that
1094 // the new top-layer will allow drawing to happen "below" it.
1095 SkRegion hole(ir);
1096 do {
1097 layer = layer->fNext;
1098 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1099 } while (layer->fNext);
1100 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101}
1102
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001103int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001104 if (0xFF == alpha) {
1105 return this->saveLayer(bounds, nullptr);
1106 } else {
1107 SkPaint tmpPaint;
1108 tmpPaint.setAlpha(alpha);
1109 return this->saveLayer(bounds, &tmpPaint);
1110 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001111}
1112
Mike Reed148b7fd2018-12-18 17:38:18 -05001113void SkCanvas::internalSaveBehind(const SkRect* localBounds) {
1114 SkIRect devBounds;
1115 if (localBounds) {
1116 SkRect tmp;
1117 fMCRec->fMatrix.mapRect(&tmp, *localBounds);
1118 if (!devBounds.intersect(tmp.round(), this->getDeviceClipBounds())) {
1119 devBounds.setEmpty();
1120 }
1121 } else {
1122 devBounds = this->getDeviceClipBounds();
1123 }
1124 if (devBounds.isEmpty()) {
1125 return;
1126 }
1127
1128 SkBaseDevice* device = this->getTopDevice();
1129 if (nullptr == device) { // Do we still need this check???
1130 return;
1131 }
1132
1133 // need the bounds relative to the device itself
1134 devBounds.offset(-device->fOrigin.fX, -device->fOrigin.fY);
1135
1136 auto backImage = device->snapBackImage(devBounds);
1137 if (!backImage) {
1138 return;
1139 }
1140
1141 // we really need the save, so we can wack the fMCRec
1142 this->checkForDeferredSave();
1143
1144 fMCRec->fBackImage.reset(new BackImage{std::move(backImage), devBounds.topLeft()});
1145
1146 SkPaint paint;
1147 paint.setBlendMode(SkBlendMode::kClear);
1148 if (localBounds) {
1149 this->drawRect(*localBounds, paint);
1150 } else {
1151 this->drawPaint(paint);
1152 }
1153}
1154
reed@android.com8a1c16f2008-12-17 15:59:43 +00001155void SkCanvas::internalRestore() {
1156 SkASSERT(fMCStack.count() != 0);
1157
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001158 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001159 DeviceCM* layer = fMCRec->fLayer; // may be null
1160 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001161 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001162
Mike Reed148b7fd2018-12-18 17:38:18 -05001163 // move this out before we do the actual restore
1164 auto backImage = std::move(fMCRec->fBackImage);
1165
reed@android.com8a1c16f2008-12-17 15:59:43 +00001166 // now do the normal restore()
1167 fMCRec->~MCRec(); // balanced in save()
1168 fMCStack.pop_back();
1169 fMCRec = (MCRec*)fMCStack.back();
1170
Mike Reedc42a1cd2017-02-14 14:25:14 -05001171 if (fMCRec) {
1172 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1173 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001174
Mike Reed148b7fd2018-12-18 17:38:18 -05001175 if (backImage) {
1176 SkPaint paint;
1177 paint.setBlendMode(SkBlendMode::kDstOver);
1178 const int x = backImage->fLoc.x();
1179 const int y = backImage->fLoc.y();
1180 this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint,
1181 nullptr, SkMatrix::I());
1182 }
1183
reed@android.com8a1c16f2008-12-17 15:59:43 +00001184 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1185 since if we're being recorded, we don't want to record this (the
1186 recorder will have already recorded the restore).
1187 */
bsalomon49f085d2014-09-05 13:34:00 -07001188 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001189 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001190 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001191 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001192 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001193 layer->fPaint.get(),
1194 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001195 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001196 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001197 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001198 delete layer;
reedb679ca82015-04-07 04:40:48 -07001199 } else {
1200 // we're at the root
reeda499f902015-05-01 09:34:31 -07001201 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001202 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001203 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001204 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001205 }
msarettfbfa2582016-08-12 08:29:08 -07001206
1207 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001208 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001209 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1210 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001211}
1212
reede8f30622016-03-23 18:59:25 -07001213sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001214 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001215 props = &fProps;
1216 }
1217 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001218}
1219
reede8f30622016-03-23 18:59:25 -07001220sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001221 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001222 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001223}
1224
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001225SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001226 return this->onImageInfo();
1227}
1228
1229SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001230 SkBaseDevice* dev = this->getDevice();
1231 if (dev) {
1232 return dev->imageInfo();
1233 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001234 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001235 }
1236}
1237
brianosman898235c2016-04-06 07:38:23 -07001238bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001239 return this->onGetProps(props);
1240}
1241
1242bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001243 SkBaseDevice* dev = this->getDevice();
1244 if (dev) {
1245 if (props) {
1246 *props = fProps;
1247 }
1248 return true;
1249 } else {
1250 return false;
1251 }
1252}
1253
reed6ceeebd2016-03-09 14:26:26 -08001254bool SkCanvas::peekPixels(SkPixmap* pmap) {
1255 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001256}
1257
reed884e97c2015-05-26 11:31:54 -07001258bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001259 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001260 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001261}
1262
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001263void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001264 SkPixmap pmap;
1265 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001266 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001267 }
1268 if (info) {
1269 *info = pmap.info();
1270 }
1271 if (rowBytes) {
1272 *rowBytes = pmap.rowBytes();
1273 }
1274 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001275 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001276 }
reed884e97c2015-05-26 11:31:54 -07001277 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001278}
1279
reed884e97c2015-05-26 11:31:54 -07001280bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001281 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001282 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001283}
1284
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001286
Florin Malita53f77bd2017-04-28 13:48:37 -04001287void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1288 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001290 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291 paint = &tmp;
1292 }
reed@google.com4b226022011-01-11 18:32:13 +00001293
Ben Wagner2c312c42018-06-27 14:46:46 -04001294 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001295
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001297 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001298 paint = &looper.paint();
1299 SkImageFilter* filter = paint->getImageFilter();
1300 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001301 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001302 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1303 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001304 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1305 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001306 }
reed@google.com76dd2772012-01-05 21:15:07 +00001307 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001308 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001309 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310 }
reeda2217ef2016-07-20 06:04:34 -07001311
reed@google.com4e2b3d32011-04-07 14:18:59 +00001312 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313}
1314
reed32704672015-12-16 08:27:10 -08001315/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001316
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001317void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001318 if (dx || dy) {
1319 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001320 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001321
reedfe69b502016-09-12 06:31:48 -07001322 // Translate shouldn't affect the is-scale-translateness of the matrix.
1323 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001324
Mike Reedc42a1cd2017-02-14 14:25:14 -05001325 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001326
reedfe69b502016-09-12 06:31:48 -07001327 this->didTranslate(dx,dy);
1328 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001329}
1330
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001331void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001332 SkMatrix m;
1333 m.setScale(sx, sy);
1334 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335}
1336
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001337void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001338 SkMatrix m;
1339 m.setRotate(degrees);
1340 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341}
1342
bungeman7438bfc2016-07-12 15:01:19 -07001343void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1344 SkMatrix m;
1345 m.setRotate(degrees, px, py);
1346 this->concat(m);
1347}
1348
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001349void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001350 SkMatrix m;
1351 m.setSkew(sx, sy);
1352 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001353}
1354
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001355void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001356 if (matrix.isIdentity()) {
1357 return;
1358 }
1359
reed2ff1fce2014-12-11 07:07:37 -08001360 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001361 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001362 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001363
Mike Reed7627fa52017-02-08 10:07:53 -05001364 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001365
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001366 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001367}
1368
reed8c30a812016-04-20 16:36:51 -07001369void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001370 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001371 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001372
Mike Reedc42a1cd2017-02-14 14:25:14 -05001373 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001374}
1375
1376void SkCanvas::setMatrix(const SkMatrix& matrix) {
1377 this->checkForDeferredSave();
1378 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001379 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001380}
1381
reed@android.com8a1c16f2008-12-17 15:59:43 +00001382void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001383 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001384}
1385
1386//////////////////////////////////////////////////////////////////////////////
1387
Mike Reedc1f77742016-12-09 09:00:50 -05001388void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001389 if (!rect.isFinite()) {
1390 return;
1391 }
reed2ff1fce2014-12-11 07:07:37 -08001392 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001393 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1394 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001395}
1396
Mike Reedc1f77742016-12-09 09:00:50 -05001397void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001398 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001399
Mike Reed7627fa52017-02-08 10:07:53 -05001400 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001401
reedc64eff52015-11-21 12:39:45 -08001402 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001403 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1404 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001405 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001406}
1407
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001408void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1409 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001410 if (fClipRestrictionRect.isEmpty()) {
1411 // we notify the device, but we *dont* resolve deferred saves (since we're just
1412 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001413 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001414 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001415 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001416 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001417 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001418 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001419 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1420 }
1421}
1422
Mike Reedc1f77742016-12-09 09:00:50 -05001423void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001424 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001425 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001426 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001427 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1428 } else {
1429 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001430 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001431}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001432
Mike Reedc1f77742016-12-09 09:00:50 -05001433void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001434 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001435
Brian Salomona3b45d42016-10-03 11:36:16 -04001436 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001437
Mike Reed7627fa52017-02-08 10:07:53 -05001438 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001439
Mike Reed20800c82017-11-15 16:09:04 -05001440 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1441 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001442 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001443}
1444
Mike Reedc1f77742016-12-09 09:00:50 -05001445void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001446 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001447 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001448
1449 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1450 SkRect r;
1451 if (path.isRect(&r)) {
1452 this->onClipRect(r, op, edgeStyle);
1453 return;
1454 }
1455 SkRRect rrect;
1456 if (path.isOval(&r)) {
1457 rrect.setOval(r);
1458 this->onClipRRect(rrect, op, edgeStyle);
1459 return;
1460 }
1461 if (path.isRRect(&rrect)) {
1462 this->onClipRRect(rrect, op, edgeStyle);
1463 return;
1464 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001465 }
robertphillips39f05382015-11-24 09:30:12 -08001466
1467 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001468}
1469
Mike Reedc1f77742016-12-09 09:00:50 -05001470void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001471 AutoValidateClip avc(this);
1472
Brian Salomona3b45d42016-10-03 11:36:16 -04001473 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001474
Mike Reed7627fa52017-02-08 10:07:53 -05001475 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476
Brian Salomona3b45d42016-10-03 11:36:16 -04001477 const SkPath* rasterClipPath = &path;
1478 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001479 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1480 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001481 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482}
1483
Mike Reedc1f77742016-12-09 09:00:50 -05001484void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001485 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001486 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001487}
1488
Mike Reedc1f77742016-12-09 09:00:50 -05001489void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001490 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001491
reed@google.com5c3d1472011-02-22 19:12:23 +00001492 AutoValidateClip avc(this);
1493
Mike Reed20800c82017-11-15 16:09:04 -05001494 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001495 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001496}
1497
reed@google.com819c9212011-02-23 18:56:55 +00001498#ifdef SK_DEBUG
1499void SkCanvas::validateClip() const {
1500 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001501 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001502 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001503 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001504 return;
1505 }
reed@google.com819c9212011-02-23 18:56:55 +00001506}
1507#endif
1508
Mike Reeda1361362017-03-07 09:37:29 -05001509bool SkCanvas::androidFramework_isClipAA() const {
1510 bool containsAA = false;
1511
1512 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1513
1514 return containsAA;
1515}
1516
1517class RgnAccumulator {
1518 SkRegion* fRgn;
1519public:
1520 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1521 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1522 SkIPoint origin = device->getOrigin();
1523 if (origin.x() | origin.y()) {
1524 rgn->translate(origin.x(), origin.y());
1525 }
1526 fRgn->op(*rgn, SkRegion::kUnion_Op);
1527 }
1528};
1529
1530void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1531 RgnAccumulator accum(rgn);
1532 SkRegion tmp;
1533
1534 rgn->setEmpty();
1535 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001536}
1537
reed@google.com5c3d1472011-02-22 19:12:23 +00001538///////////////////////////////////////////////////////////////////////////////
1539
reed@google.com754de5f2014-02-24 19:38:20 +00001540bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001541 return fMCRec->fRasterClip.isEmpty();
1542
1543 // TODO: should we only use the conservative answer in a recording canvas?
1544#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001545 SkBaseDevice* dev = this->getTopDevice();
1546 // if no device we return true
1547 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001548#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001549}
1550
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001551bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001552 SkBaseDevice* dev = this->getTopDevice();
1553 // if no device we return false
1554 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001555}
1556
msarettfbfa2582016-08-12 08:29:08 -07001557static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1558#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1559 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1560 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1561 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1562 return 0xF != _mm_movemask_ps(mask);
1563#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1564 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1565 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1566 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1567 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1568#else
1569 SkRect devRectAsRect;
1570 SkRect devClipAsRect;
1571 devRect.store(&devRectAsRect.fLeft);
1572 devClip.store(&devClipAsRect.fLeft);
1573 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1574#endif
1575}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001576
msarettfbfa2582016-08-12 08:29:08 -07001577// It's important for this function to not be inlined. Otherwise the compiler will share code
1578// between the fast path and the slow path, resulting in two slow paths.
1579static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1580 const SkMatrix& matrix) {
1581 SkRect deviceRect;
1582 matrix.mapRect(&deviceRect, src);
1583 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1584}
1585
1586bool SkCanvas::quickReject(const SkRect& src) const {
1587#ifdef SK_DEBUG
1588 // Verify that fDeviceClipBounds are set properly.
1589 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001590 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001591 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001592 } else {
msarettfbfa2582016-08-12 08:29:08 -07001593 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001594 }
msarettfbfa2582016-08-12 08:29:08 -07001595
msarett9637ea92016-08-18 14:03:30 -07001596 // Verify that fIsScaleTranslate is set properly.
1597 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001598#endif
1599
msarett9637ea92016-08-18 14:03:30 -07001600 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001601 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1602 }
1603
1604 // We inline the implementation of mapScaleTranslate() for the fast path.
1605 float sx = fMCRec->fMatrix.getScaleX();
1606 float sy = fMCRec->fMatrix.getScaleY();
1607 float tx = fMCRec->fMatrix.getTranslateX();
1608 float ty = fMCRec->fMatrix.getTranslateY();
1609 Sk4f scale(sx, sy, sx, sy);
1610 Sk4f trans(tx, ty, tx, ty);
1611
1612 // Apply matrix.
1613 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1614
1615 // Make sure left < right, top < bottom.
1616 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1617 Sk4f min = Sk4f::Min(ltrb, rblt);
1618 Sk4f max = Sk4f::Max(ltrb, rblt);
1619 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1620 // ARM this sequence generates the fastest (a single instruction).
1621 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1622
1623 // Check if the device rect is NaN or outside the clip.
1624 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001625}
1626
reed@google.com3b3e8952012-08-16 20:53:31 +00001627bool SkCanvas::quickReject(const SkPath& path) const {
1628 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001629}
1630
Mike Klein83c8dd92017-11-28 17:08:45 -05001631SkRect SkCanvas::getLocalClipBounds() const {
1632 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001633 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001634 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001635 }
1636
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001637 SkMatrix inverse;
1638 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001639 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001640 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001641 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001642
Mike Reed42e8c532017-01-23 14:09:13 -05001643 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001644 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001645 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001646
Mike Reedb57b9312018-04-23 12:12:54 -04001647 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001648 inverse.mapRect(&bounds, r);
1649 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001650}
1651
Mike Klein83c8dd92017-11-28 17:08:45 -05001652SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001653 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001654}
1655
reed@android.com8a1c16f2008-12-17 15:59:43 +00001656const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001657 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001658}
1659
Brian Osman11052242016-10-27 14:47:55 -04001660GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001661 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001662 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001663}
1664
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001665GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001666 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001667 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001668}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001669
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001670void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1671 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001672 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001673 if (outer.isEmpty()) {
1674 return;
1675 }
1676 if (inner.isEmpty()) {
1677 this->drawRRect(outer, paint);
1678 return;
1679 }
1680
1681 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001682 // be able to return ...
1683 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001684 //
1685 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001686 if (!outer.getBounds().contains(inner.getBounds())) {
1687 return;
1688 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001689
1690 this->onDrawDRRect(outer, inner, paint);
1691}
1692
reed41af9662015-01-05 07:49:08 -08001693void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001694 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001695 this->onDrawPaint(paint);
1696}
1697
1698void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001699 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001700 // To avoid redundant logic in our culling code and various backends, we always sort rects
1701 // before passing them along.
1702 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001703}
1704
msarettdca352e2016-08-26 06:37:45 -07001705void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001706 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001707 if (region.isEmpty()) {
1708 return;
1709 }
1710
1711 if (region.isRect()) {
1712 return this->drawIRect(region.getBounds(), paint);
1713 }
1714
1715 this->onDrawRegion(region, paint);
1716}
1717
reed41af9662015-01-05 07:49:08 -08001718void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001719 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001720 // To avoid redundant logic in our culling code and various backends, we always sort rects
1721 // before passing them along.
1722 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001723}
1724
1725void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001726 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001727 this->onDrawRRect(rrect, paint);
1728}
1729
1730void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001731 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001732 this->onDrawPoints(mode, count, pts, paint);
1733}
1734
Mike Reede88a1cb2017-03-17 09:50:46 -04001735void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1736 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001737 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001738 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001739 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1740 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001741 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001742}
1743
1744void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001745 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001746 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001747 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1748}
1749
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001750void SkCanvas::drawVertices(const sk_sp<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.get(), bones, boneCount, mode, paint);
1756}
1757
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001758void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1759 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001760 TRACE_EVENT0("skia", TRACE_FUNC);
1761 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001762 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001763 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001764}
1765
1766void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001767 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001768 this->onDrawPath(path, paint);
1769}
1770
reeda85d4d02015-05-06 12:56:48 -07001771void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001772 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001773 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001774 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001775}
1776
Mike Reedc4e31092018-01-30 11:15:27 -05001777// Returns true if the rect can be "filled" : non-empty and finite
1778static bool fillable(const SkRect& r) {
1779 SkScalar w = r.width();
1780 SkScalar h = r.height();
1781 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1782}
1783
reede47829b2015-08-06 10:02:53 -07001784void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1785 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001786 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001787 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001788 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001789 return;
1790 }
1791 this->onDrawImageRect(image, &src, dst, paint, constraint);
1792}
reed41af9662015-01-05 07:49:08 -08001793
reed84984ef2015-07-17 07:09:43 -07001794void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1795 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001796 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001797 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001798}
1799
Brian Salomonf08002c2018-10-26 16:15:46 -04001800void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001801 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001802 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001803 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001804}
reede47829b2015-08-06 10:02:53 -07001805
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001806namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001807class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001808public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001809 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1810 if (!origPaint) {
1811 return;
1812 }
1813 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1814 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1815 }
1816 if (origPaint->getMaskFilter()) {
1817 fPaint.writable()->setMaskFilter(nullptr);
1818 }
1819 if (origPaint->isAntiAlias()) {
1820 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001821 }
1822 }
1823
1824 const SkPaint* get() const {
1825 return fPaint;
1826 }
1827
1828private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001829 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001830};
1831} // namespace
1832
reed4c21dc52015-06-25 12:32:03 -07001833void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1834 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001835 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001836 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001837 if (dst.isEmpty()) {
1838 return;
1839 }
msarett552bca92016-08-03 06:53:26 -07001840 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001841 LatticePaint latticePaint(paint);
1842 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001843 } else {
reede47829b2015-08-06 10:02:53 -07001844 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001845 }
reed4c21dc52015-06-25 12:32:03 -07001846}
1847
msarett16882062016-08-16 09:31:08 -07001848void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1849 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001850 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001851 RETURN_ON_NULL(image);
1852 if (dst.isEmpty()) {
1853 return;
1854 }
msarett71df2d72016-09-30 12:41:42 -07001855
1856 SkIRect bounds;
1857 Lattice latticePlusBounds = lattice;
1858 if (!latticePlusBounds.fBounds) {
1859 bounds = SkIRect::MakeWH(image->width(), image->height());
1860 latticePlusBounds.fBounds = &bounds;
1861 }
1862
1863 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001864 LatticePaint latticePaint(paint);
1865 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001866 } else {
1867 this->drawImageRect(image, dst, paint);
1868 }
1869}
1870
Brian Salomon1da5cad2018-11-21 09:21:18 -05001871void SkCanvas::experimental_DrawImageSetV1(const ImageSetEntry imageSet[], int cnt,
1872 SkFilterQuality filterQuality, SkBlendMode mode) {
1873 TRACE_EVENT0("skia", TRACE_FUNC);
1874 RETURN_ON_NULL(imageSet);
1875 RETURN_ON_FALSE(cnt);
1876
Brian Salomond003d222018-11-26 13:25:05 -05001877 this->onDrawImageSet(imageSet, cnt, filterQuality, mode);
Brian Salomon1da5cad2018-11-21 09:21:18 -05001878}
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
msarett44df6512016-08-25 13:54:30 -07002090void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002091 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002092 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002093 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002094 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2095 return;
2096 }
msarett44df6512016-08-25 13:54:30 -07002097 }
2098
Ben Wagner2c312c42018-06-27 14:46:46 -04002099 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002100
2101 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002102 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002103 }
2104
2105 LOOPER_END
2106}
2107
reed41af9662015-01-05 07:49:08 -08002108void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002109 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002110 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002111 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002112 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002113 return;
2114 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002115 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002116
Ben Wagner2c312c42018-06-27 14:46:46 -04002117 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002118
2119 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002120 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002121 }
2122
2123 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002124}
2125
bsalomonac3aa242016-08-19 11:25:19 -07002126void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2127 SkScalar sweepAngle, bool useCenter,
2128 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002129 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002130 if (paint.canComputeFastBounds()) {
2131 SkRect storage;
2132 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002133 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002134 return;
2135 }
bsalomonac3aa242016-08-19 11:25:19 -07002136 }
2137
Ben Wagner2c312c42018-06-27 14:46:46 -04002138 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002139
2140 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002141 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002142 }
2143
2144 LOOPER_END
2145}
2146
reed41af9662015-01-05 07:49:08 -08002147void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002148 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002149 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002150 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2151 return;
2152 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002153 }
2154
2155 if (rrect.isRect()) {
2156 // call the non-virtual version
2157 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002158 return;
2159 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002160 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002161 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2162 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002163 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002164
Ben Wagner2c312c42018-06-27 14:46:46 -04002165 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002166
2167 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002168 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002169 }
2170
2171 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002172}
2173
Mike Reed822128b2017-02-28 16:41:03 -05002174void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002175 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002176 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002177 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2178 return;
2179 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002180 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002181
Ben Wagner2c312c42018-06-27 14:46:46 -04002182 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002183
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002184 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002185 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002186 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002187
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002188 LOOPER_END
2189}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002190
reed41af9662015-01-05 07:49:08 -08002191void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002192 if (!path.isFinite()) {
2193 return;
2194 }
2195
Mike Reed822128b2017-02-28 16:41:03 -05002196 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002197 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002198 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002199 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2200 return;
2201 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002202 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002203
Mike Reed822128b2017-02-28 16:41:03 -05002204 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002205 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002206 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002207 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002208 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002209 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002210
Ben Wagner2c312c42018-06-27 14:46:46 -04002211 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002212
2213 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002214 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002215 }
2216
reed@google.com4e2b3d32011-04-07 14:18:59 +00002217 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002218}
2219
reed262a71b2015-12-05 13:07:27 -08002220bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002221 if (!paint.getImageFilter()) {
2222 return false;
2223 }
2224
2225 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002226 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002227 return false;
2228 }
2229
2230 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2231 // Once we can filter and the filter will return a result larger than itself, we should be
2232 // able to remove this constraint.
2233 // skbug.com/4526
2234 //
2235 SkPoint pt;
2236 ctm.mapXY(x, y, &pt);
2237 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2238 return ir.contains(fMCRec->fRasterClip.getBounds());
2239}
2240
Mike Reedf441cfc2018-04-11 14:50:16 -04002241// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2242// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2243// null.
2244static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2245 if (paintParam) {
2246 *real = *paintParam;
2247 real->setStyle(SkPaint::kFill_Style);
2248 real->setPathEffect(nullptr);
2249 paintParam = real;
2250 }
2251 return paintParam;
2252}
2253
reeda85d4d02015-05-06 12:56:48 -07002254void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002255 SkPaint realPaint;
2256 paint = init_image_paint(&realPaint, paint);
2257
reeda85d4d02015-05-06 12:56:48 -07002258 SkRect bounds = SkRect::MakeXYWH(x, y,
2259 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002260 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002261 SkRect tmp = bounds;
2262 if (paint) {
2263 paint->computeFastBounds(tmp, &tmp);
2264 }
2265 if (this->quickReject(tmp)) {
2266 return;
2267 }
reeda85d4d02015-05-06 12:56:48 -07002268 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002269 // At this point we need a real paint object. If the caller passed null, then we should
2270 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2271 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2272 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002273
reeda2217ef2016-07-20 06:04:34 -07002274 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002275 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2276 *paint);
2277 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002278 special = this->getDevice()->makeSpecial(image);
2279 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002280 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002281 }
2282 }
2283
reed262a71b2015-12-05 13:07:27 -08002284 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2285
reeda85d4d02015-05-06 12:56:48 -07002286 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002287 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002288 if (special) {
2289 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002290 iter.fDevice->ctm().mapXY(x, y, &pt);
2291 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002292 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002293 SkScalarRoundToInt(pt.fY), pnt,
2294 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002295 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002296 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002297 }
reeda85d4d02015-05-06 12:56:48 -07002298 }
halcanary9d524f22016-03-29 09:03:52 -07002299
reeda85d4d02015-05-06 12:56:48 -07002300 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002301}
2302
reed41af9662015-01-05 07:49:08 -08002303void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002304 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002305 SkPaint realPaint;
2306 paint = init_image_paint(&realPaint, paint);
2307
halcanary96fcdcc2015-08-27 07:41:13 -07002308 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002309 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002310 if (paint) {
2311 paint->computeFastBounds(dst, &storage);
2312 }
2313 if (this->quickReject(storage)) {
2314 return;
2315 }
reeda85d4d02015-05-06 12:56:48 -07002316 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002317 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002318
Ben Wagner2c312c42018-06-27 14:46:46 -04002319 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002320
reeda85d4d02015-05-06 12:56:48 -07002321 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002322 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002323 }
halcanary9d524f22016-03-29 09:03:52 -07002324
reeda85d4d02015-05-06 12:56:48 -07002325 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002326}
2327
reed41af9662015-01-05 07:49:08 -08002328void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002329 SkDEBUGCODE(bitmap.validate();)
2330
reed33366972015-10-08 09:22:02 -07002331 if (bitmap.drawsNothing()) {
2332 return;
2333 }
2334
Mike Reedf441cfc2018-04-11 14:50:16 -04002335 SkPaint realPaint;
2336 init_image_paint(&realPaint, paint);
2337 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002338
Mike Reed822128b2017-02-28 16:41:03 -05002339 SkRect bounds;
2340 bitmap.getBounds(&bounds);
2341 bounds.offset(x, y);
2342 bool canFastBounds = paint->canComputeFastBounds();
2343 if (canFastBounds) {
2344 SkRect storage;
2345 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002346 return;
2347 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002348 }
reed@google.com4b226022011-01-11 18:32:13 +00002349
reeda2217ef2016-07-20 06:04:34 -07002350 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002351 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2352 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002353 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002354 special = this->getDevice()->makeSpecial(bitmap);
2355 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002356 drawAsSprite = false;
2357 }
2358 }
2359
Mike Reed822128b2017-02-28 16:41:03 -05002360 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002361
2362 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002363 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002364 if (special) {
reed262a71b2015-12-05 13:07:27 -08002365 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002366 iter.fDevice->ctm().mapXY(x, y, &pt);
2367 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002368 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002369 SkScalarRoundToInt(pt.fY), pnt,
2370 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002371 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002372 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002373 }
reed33366972015-10-08 09:22:02 -07002374 }
msarettfbfa2582016-08-12 08:29:08 -07002375
reed33366972015-10-08 09:22:02 -07002376 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002377}
2378
reed@google.com9987ec32011-09-07 11:57:52 +00002379// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002380void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002381 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002382 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002383 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002384 return;
2385 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002386
halcanary96fcdcc2015-08-27 07:41:13 -07002387 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002388 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002389 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2390 return;
2391 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002392 }
reed@google.com3d608122011-11-21 15:16:16 +00002393
reed@google.com33535f32012-09-25 15:37:50 +00002394 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002395 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002396 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002397 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002398
Ben Wagner2c312c42018-06-27 14:46:46 -04002399 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002400
reed@google.com33535f32012-09-25 15:37:50 +00002401 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002402 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002403 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002404
reed@google.com33535f32012-09-25 15:37:50 +00002405 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002406}
2407
reed41af9662015-01-05 07:49:08 -08002408void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002409 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002410 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002411 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002412}
2413
reed4c21dc52015-06-25 12:32:03 -07002414void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2415 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002416 SkPaint realPaint;
2417 paint = init_image_paint(&realPaint, paint);
2418
halcanary96fcdcc2015-08-27 07:41:13 -07002419 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002420 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002421 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2422 return;
2423 }
reed@google.com3d608122011-11-21 15:16:16 +00002424 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002425 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002426
Ben Wagner2c312c42018-06-27 14:46:46 -04002427 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002428
reed4c21dc52015-06-25 12:32:03 -07002429 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002430 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002431 }
halcanary9d524f22016-03-29 09:03:52 -07002432
reed4c21dc52015-06-25 12:32:03 -07002433 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002434}
2435
reed41af9662015-01-05 07:49:08 -08002436void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2437 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002438 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002439 SkPaint realPaint;
2440 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002441
halcanary96fcdcc2015-08-27 07:41:13 -07002442 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002443 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002444 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2445 return;
2446 }
reed4c21dc52015-06-25 12:32:03 -07002447 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002448 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002449
Ben Wagner2c312c42018-06-27 14:46:46 -04002450 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002451
reed4c21dc52015-06-25 12:32:03 -07002452 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002453 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002454 }
halcanary9d524f22016-03-29 09:03:52 -07002455
reed4c21dc52015-06-25 12:32:03 -07002456 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002457}
2458
msarett16882062016-08-16 09:31:08 -07002459void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2460 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002461 SkPaint realPaint;
2462 paint = init_image_paint(&realPaint, paint);
2463
msarett16882062016-08-16 09:31:08 -07002464 if (nullptr == paint || paint->canComputeFastBounds()) {
2465 SkRect storage;
2466 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2467 return;
2468 }
2469 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002470 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002471
Ben Wagner2c312c42018-06-27 14:46:46 -04002472 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002473
2474 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002475 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002476 }
2477
2478 LOOPER_END
2479}
2480
Brian Salomond003d222018-11-26 13:25:05 -05002481void SkCanvas::onDrawImageSet(const ImageSetEntry imageSet[], int count,
Brian Salomond7065e72018-10-12 11:42:02 -04002482 SkFilterQuality filterQuality, SkBlendMode mode) {
2483 SkPaint paint;
Brian Salomon23356442018-11-30 15:33:19 -05002484 LOOPER_BEGIN(paint, nullptr)
Brian Salomond7065e72018-10-12 11:42:02 -04002485 while (iter.next()) {
Brian Salomond003d222018-11-26 13:25:05 -05002486 iter.fDevice->drawImageSet(imageSet, count, filterQuality, mode);
Brian Salomond7065e72018-10-12 11:42:02 -04002487 }
2488 LOOPER_END
2489}
2490
msarett16882062016-08-16 09:31:08 -07002491void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2492 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002493 SkPaint realPaint;
2494 paint = init_image_paint(&realPaint, paint);
2495
msarett16882062016-08-16 09:31:08 -07002496 if (nullptr == paint || paint->canComputeFastBounds()) {
2497 SkRect storage;
2498 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2499 return;
2500 }
2501 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002502 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002503
Ben Wagner2c312c42018-06-27 14:46:46 -04002504 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002505
2506 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002507 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002508 }
2509
2510 LOOPER_END
2511}
2512
fmalita00d5c2c2014-08-21 08:53:26 -07002513void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2514 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002515 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002516 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002517 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002518 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002519 SkRect tmp;
2520 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2521 return;
2522 }
2523 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002524 }
2525
fmalita024f9962015-03-03 19:08:17 -08002526 // We cannot filter in the looper as we normally do, because the paint is
2527 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002528 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002529
fmalitaaa1b9122014-08-28 14:32:24 -07002530 while (iter.next()) {
Mike Reed30cf62b2018-12-20 11:18:24 -05002531 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, {x, y}, iter.fDevice);
fmalita00d5c2c2014-08-21 08:53:26 -07002532 }
2533
fmalitaaa1b9122014-08-28 14:32:24 -07002534 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002535}
2536
Mike Reed358fcad2018-11-23 15:27:51 -05002537// These call the (virtual) onDraw... method
Mike Reed7d1eb332018-12-04 17:35:56 -05002538void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
Mike Reed358fcad2018-11-23 15:27:51 -05002539 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2540 TRACE_EVENT0("skia", TRACE_FUNC);
2541 if (byteLength) {
2542 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002543 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
Mike Reed358fcad2018-11-23 15:27:51 -05002544 }
2545}
reed@google.come0d9ce82014-04-23 04:00:17 +00002546void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2547 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002548 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002549 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002550 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
Mike Reed704a3422018-12-06 15:44:14 -05002551 const SkFont font = SkFont::LEGACY_ExtractFromPaint(paint);
Mike Reed023403b2019-01-07 12:57:10 -05002552 const SkTextEncoding encoding = paint.private_internal_getTextEncoding();
Mike Reed704a3422018-12-06 15:44:14 -05002553 this->drawTextBlob(SkTextBlob::MakeFromText(text, byteLength, font, encoding), x, y, paint);
reedac095542016-08-04 15:54:41 -07002554 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002555}
fmalita00d5c2c2014-08-21 08:53:26 -07002556void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2557 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002558 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002559 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002560 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002561 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002562}
reed@google.come0d9ce82014-04-23 04:00:17 +00002563
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002564void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002565 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002566 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002567
2568 while (iter.next()) {
2569 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002570 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002571 }
2572
2573 LOOPER_END
2574}
2575
dandovb3c9d1c2014-08-12 08:34:29 -07002576void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002577 const SkPoint texCoords[4], SkBlendMode bmode,
2578 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002579 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002580 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002581 return;
2582 }
mtklein6cfa73a2014-08-13 13:33:49 -07002583
Mike Reedfaba3712016-11-03 14:45:31 -04002584 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002585}
2586
2587void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002588 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002589 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002590 // Since a patch is always within the convex hull of the control points, we discard it when its
2591 // bounding rectangle is completely outside the current clip.
2592 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002593 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002594 if (this->quickReject(bounds)) {
2595 return;
2596 }
mtklein6cfa73a2014-08-13 13:33:49 -07002597
Ben Wagner2c312c42018-06-27 14:46:46 -04002598 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002599
dandovecfff212014-08-04 10:02:00 -07002600 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002601 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002602 }
mtklein6cfa73a2014-08-13 13:33:49 -07002603
dandovecfff212014-08-04 10:02:00 -07002604 LOOPER_END
2605}
2606
reeda8db7282015-07-07 10:22:31 -07002607void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002608#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002609 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002610#endif
reede3b38ce2016-01-08 09:18:44 -08002611 RETURN_ON_NULL(dr);
2612 if (x || y) {
2613 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2614 this->onDrawDrawable(dr, &matrix);
2615 } else {
2616 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002617 }
2618}
2619
reeda8db7282015-07-07 10:22:31 -07002620void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002621#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002622 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002623#endif
reede3b38ce2016-01-08 09:18:44 -08002624 RETURN_ON_NULL(dr);
2625 if (matrix && matrix->isIdentity()) {
2626 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002627 }
reede3b38ce2016-01-08 09:18:44 -08002628 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002629}
2630
2631void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002632 // drawable bounds are no longer reliable (e.g. android displaylist)
2633 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002634 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002635}
2636
reed71c3c762015-06-24 10:29:17 -07002637void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002638 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002639 const SkRect* cull, const SkPaint* paint) {
2640 if (cull && this->quickReject(*cull)) {
2641 return;
2642 }
2643
2644 SkPaint pnt;
2645 if (paint) {
2646 pnt = *paint;
2647 }
halcanary9d524f22016-03-29 09:03:52 -07002648
Ben Wagner2c312c42018-06-27 14:46:46 -04002649 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002650 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002651 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002652 }
2653 LOOPER_END
2654}
2655
reedf70b5312016-03-04 16:36:20 -08002656void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2657 SkASSERT(key);
2658
2659 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002660 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002661 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002662 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002663 }
2664 LOOPER_END
2665}
2666
reed@android.com8a1c16f2008-12-17 15:59:43 +00002667//////////////////////////////////////////////////////////////////////////////
2668// These methods are NOT virtual, and therefore must call back into virtual
2669// methods, rather than actually drawing themselves.
2670//////////////////////////////////////////////////////////////////////////////
2671
reed374772b2016-10-05 17:33:02 -07002672void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002673 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002674 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002675 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002676 this->drawPaint(paint);
2677}
2678
2679void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002680 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002681 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2682}
2683
Mike Reed3661bc92017-02-22 13:21:42 -05002684void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002685 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002686 pts[0].set(x0, y0);
2687 pts[1].set(x1, y1);
2688 this->drawPoints(kLines_PointMode, 2, pts, paint);
2689}
2690
Mike Reed3661bc92017-02-22 13:21:42 -05002691void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002692 if (radius < 0) {
2693 radius = 0;
2694 }
2695
2696 SkRect r;
2697 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002698 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002699}
2700
2701void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2702 const SkPaint& paint) {
2703 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002704 SkRRect rrect;
2705 rrect.setRectXY(r, rx, ry);
2706 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002707 } else {
2708 this->drawRect(r, paint);
2709 }
2710}
2711
reed@android.com8a1c16f2008-12-17 15:59:43 +00002712void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2713 SkScalar sweepAngle, bool useCenter,
2714 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002715 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002716 if (oval.isEmpty() || !sweepAngle) {
2717 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002718 }
bsalomon21af9ca2016-08-25 12:29:23 -07002719 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002720}
2721
reed@android.comf76bacf2009-05-13 14:00:33 +00002722///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002723#ifdef SK_DISABLE_SKPICTURE
2724void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002725
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002726
2727void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2728 const SkPaint* paint) {}
2729#else
Mike Klein88d90712018-01-27 17:30:04 +00002730/**
2731 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2732 * against the playback cost of recursing into the subpicture to get at its actual ops.
2733 *
2734 * For now we pick a conservatively small value, though measurement (and other heuristics like
2735 * the type of ops contained) may justify changing this value.
2736 */
2737#define kMaxPictureOpsToUnrollInsteadOfRef 1
2738
reedd5fa1a42014-08-09 11:08:05 -07002739void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002740 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002741 RETURN_ON_NULL(picture);
2742
reede3b38ce2016-01-08 09:18:44 -08002743 if (matrix && matrix->isIdentity()) {
2744 matrix = nullptr;
2745 }
Mike Klein88d90712018-01-27 17:30:04 +00002746 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2747 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2748 picture->playback(this);
2749 } else {
2750 this->onDrawPicture(picture, matrix, paint);
2751 }
reedd5fa1a42014-08-09 11:08:05 -07002752}
robertphillips9b14f262014-06-04 05:40:44 -07002753
reedd5fa1a42014-08-09 11:08:05 -07002754void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2755 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002756 if (!paint || paint->canComputeFastBounds()) {
2757 SkRect bounds = picture->cullRect();
2758 if (paint) {
2759 paint->computeFastBounds(bounds, &bounds);
2760 }
2761 if (matrix) {
2762 matrix->mapRect(&bounds);
2763 }
2764 if (this->quickReject(bounds)) {
2765 return;
2766 }
2767 }
2768
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002769 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002770 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002771}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002772#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002773
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774///////////////////////////////////////////////////////////////////////////////
2775///////////////////////////////////////////////////////////////////////////////
2776
reed3aafe112016-08-18 12:45:34 -07002777SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002778 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002779
2780 SkASSERT(canvas);
2781
reed3aafe112016-08-18 12:45:34 -07002782 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002783 fDone = !fImpl->next();
2784}
2785
2786SkCanvas::LayerIter::~LayerIter() {
2787 fImpl->~SkDrawIter();
2788}
2789
2790void SkCanvas::LayerIter::next() {
2791 fDone = !fImpl->next();
2792}
2793
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002794SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002795 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796}
2797
2798const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002799 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002800}
2801
2802const SkPaint& SkCanvas::LayerIter::paint() const {
2803 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002804 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002805 paint = &fDefaultPaint;
2806 }
2807 return *paint;
2808}
2809
Mike Reedca37f322018-03-08 13:22:16 -05002810SkIRect SkCanvas::LayerIter::clipBounds() const {
2811 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002812}
2813
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2815int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002816
2817///////////////////////////////////////////////////////////////////////////////
2818
Mike Reed5df49342016-11-12 08:06:55 -06002819std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002820 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002821 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002822 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002823 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002824
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002825 SkBitmap bitmap;
2826 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002827 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002828 }
Mike Reed12f77342017-11-08 11:19:52 -05002829
2830 return props ?
2831 skstd::make_unique<SkCanvas>(bitmap, *props) :
2832 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002833}
reedd5fa1a42014-08-09 11:08:05 -07002834
2835///////////////////////////////////////////////////////////////////////////////
2836
Florin Malitaee424ac2016-12-01 12:47:59 -05002837SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002838 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002839
Florin Malita439ace92016-12-02 12:05:41 -05002840SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002841 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002842
Herb Derbyefe39bc2018-05-01 17:06:20 -04002843SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002844 : INHERITED(device) {}
2845
Florin Malitaee424ac2016-12-01 12:47:59 -05002846SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2847 (void)this->INHERITED::getSaveLayerStrategy(rec);
2848 return kNoLayer_SaveLayerStrategy;
2849}
2850
Mike Reed148b7fd2018-12-18 17:38:18 -05002851bool SkNoDrawCanvas::onDoSaveBehind(const SkRect*) {
2852 return false;
2853}
2854
Florin Malitaee424ac2016-12-01 12:47:59 -05002855///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002856
reed73603f32016-09-20 08:42:38 -07002857static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2858static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2859static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2860static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2861static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2862static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002863
2864///////////////////////////////////////////////////////////////////////////////////////////////////
2865
2866SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2867 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002868 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002869 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2870 SkIPoint origin = dev->getOrigin();
2871 SkMatrix ctm = this->getTotalMatrix();
2872 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2873
2874 SkIRect clip = fMCRec->fRasterClip.getBounds();
2875 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002876 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002877 clip.setEmpty();
2878 }
2879
2880 fAllocator->updateHandle(handle, ctm, clip);
2881 return handle;
2882 }
2883 return nullptr;
2884}
2885
2886static bool install(SkBitmap* bm, const SkImageInfo& info,
2887 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002888 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002889}
2890
2891SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2892 SkBitmap* bm) {
2893 SkRasterHandleAllocator::Rec rec;
2894 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2895 return nullptr;
2896 }
2897 return rec.fHandle;
2898}
2899
2900std::unique_ptr<SkCanvas>
2901SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2902 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04002903 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05002904 return nullptr;
2905 }
2906
2907 SkBitmap bm;
2908 Handle hndl;
2909
2910 if (rec) {
2911 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2912 } else {
2913 hndl = alloc->allocBitmap(info, &bm);
2914 }
2915 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2916}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002917
2918///////////////////////////////////////////////////////////////////////////////////////////////////
2919
2920