blob: d8482f699a0c81ef36ec7bae1e3cc2bfc40765a5 [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"
Hal Canaryc640d0d2018-06-13 09:59:02 -040018#include "SkDrawable.h"
Herb Derby41f4f312018-06-06 17:45:53 +000019#include "SkGlyphCache.h"
20#include "SkGlyphRun.h"
piotaixrb5fae932014-09-24 13:03:30 -070021#include "SkImage.h"
senorblanco900c3672016-04-27 11:31:23 -070022#include "SkImageFilter.h"
23#include "SkImageFilterCache.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040024#include "SkImage_Base.h"
msarettc573a402016-08-02 08:05:56 -070025#include "SkLatticeIter.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040026#include "SkMSAN.h"
Mike Reed5df49342016-11-12 08:06:55 -060027#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080028#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000029#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050030#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070031#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070032#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070033#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040034#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000035#include "SkPicture.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040036#include "SkRRect.h"
reed@google.com00177082011-10-12 14:34:30 +000037#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050038#include "SkRasterHandleAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080039#include "SkSpecialImage.h"
Herb Derby41f4f312018-06-06 17:45:53 +000040#include "SkStrikeCache.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040041#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000042#include "SkSurface_Base.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040043#include "SkTLazy.h"
fmalita7ba7aa72014-08-29 09:46:36 -070044#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000045#include "SkTextFormatParams.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040046#include "SkTo.h"
danakj8f757f52014-11-04 11:48:43 -080047#include "SkTraceEvent.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040048#include "SkVertices.h"
49
bungemand3ebb482015-08-05 13:57:49 -070050#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000051
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080053#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050054#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000055#endif
56
reede3b38ce2016-01-08 09:18:44 -080057#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050058#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080059
Mike Reed139e5e02017-03-08 11:29:33 -050060///////////////////////////////////////////////////////////////////////////////////////////////////
61
reedc83a2972015-07-16 07:40:45 -070062/*
63 * Return true if the drawing this rect would hit every pixels in the canvas.
64 *
65 * Returns false if
66 * - rect does not contain the canvas' bounds
67 * - paint is not fill
68 * - paint would blur or otherwise change the coverage of the rect
69 */
70bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
71 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070072 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
73 (int)kNone_ShaderOverrideOpacity,
74 "need_matching_enums0");
75 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
76 (int)kOpaque_ShaderOverrideOpacity,
77 "need_matching_enums1");
78 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
79 (int)kNotOpaque_ShaderOverrideOpacity,
80 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070081
82 const SkISize size = this->getBaseLayerSize();
83 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050084
85 // if we're clipped at all, we can't overwrite the entire surface
86 {
87 SkBaseDevice* base = this->getDevice();
88 SkBaseDevice* top = this->getTopDevice();
89 if (base != top) {
90 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
91 }
92 if (!base->clipIsWideOpen()) {
93 return false;
94 }
reedc83a2972015-07-16 07:40:45 -070095 }
96
97 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070098 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070099 return false; // conservative
100 }
halcanaryc5769b22016-08-10 07:13:21 -0700101
102 SkRect devRect;
103 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
104 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700105 return false;
106 }
107 }
108
109 if (paint) {
110 SkPaint::Style paintStyle = paint->getStyle();
111 if (!(paintStyle == SkPaint::kFill_Style ||
112 paintStyle == SkPaint::kStrokeAndFill_Style)) {
113 return false;
114 }
115 if (paint->getMaskFilter() || paint->getLooper()
116 || paint->getPathEffect() || paint->getImageFilter()) {
117 return false; // conservative
118 }
119 }
120 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
121}
122
123///////////////////////////////////////////////////////////////////////////////////////////////////
124
reed@google.comda17f752012-08-16 18:27:05 +0000125// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126//#define SK_TRACE_SAVERESTORE
127
128#ifdef SK_TRACE_SAVERESTORE
129 static int gLayerCounter;
130 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
131 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
132
133 static int gRecCounter;
134 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
135 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
136
137 static int gCanvasCounter;
138 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
139 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
140#else
141 #define inc_layer()
142 #define dec_layer()
143 #define inc_rec()
144 #define dec_rec()
145 #define inc_canvas()
146 #define dec_canvas()
147#endif
148
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000149typedef SkTLazy<SkPaint> SkLazyPaint;
150
reedc83a2972015-07-16 07:40:45 -0700151void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000152 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700153 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
154 ? SkSurface::kDiscard_ContentChangeMode
155 : SkSurface::kRetain_ContentChangeMode);
156 }
157}
158
159void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
160 ShaderOverrideOpacity overrideOpacity) {
161 if (fSurfaceBase) {
162 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
163 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
164 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
165 // and therefore we don't care which mode we're in.
166 //
167 if (fSurfaceBase->outstandingImageSnapshot()) {
168 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
169 mode = SkSurface::kDiscard_ContentChangeMode;
170 }
171 }
172 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000173 }
174}
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000178/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 The clip/matrix/proc are fields that reflect the top of the save/restore
180 stack. Whenever the canvas changes, it marks a dirty flag, and then before
181 these are used (assuming we're not on a layer) we rebuild these cache
182 values: they reflect the top of the save stack, but translated and clipped
183 by the device's XY offset and bitmap-bounds.
184*/
185struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400186 DeviceCM* fNext;
187 sk_sp<SkBaseDevice> fDevice;
188 SkRasterClip fClip;
189 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
190 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400191 sk_sp<SkImage> fClipImage;
192 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193
Florin Malita53f77bd2017-04-28 13:48:37 -0400194 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000195 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700196 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400197 , fDevice(std::move(device))
198 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700199 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000200 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400201 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400202 {}
reed@google.com4b226022011-01-11 18:32:13 +0000203
mtkleinfeaadee2015-04-08 11:25:48 -0700204 void reset(const SkIRect& bounds) {
205 SkASSERT(!fPaint);
206 SkASSERT(!fNext);
207 SkASSERT(fDevice);
208 fClip.setRect(bounds);
209 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210};
211
212/* This is the record we keep for each save/restore level in the stack.
213 Since a level optionally copies the matrix and/or stack, we have pointers
214 for these fields. If the value is copied for this level, the copy is
215 stored in the ...Storage field, and the pointer points to that. If the
216 value is not copied for this level, we ignore ...Storage, and just point
217 at the corresponding value in the previous level in the stack.
218*/
219class SkCanvas::MCRec {
220public:
reedd9544982014-09-09 18:46:22 -0700221 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 /* If there are any layers in the stack, this points to the top-most
223 one that is at or below this level in the stack (so we know what
224 bitmap/device to draw into from this level. This value is NOT
225 reference counted, since the real owner is either our fLayer field,
226 or a previous one in a lower level.)
227 */
Mike Reeda1361362017-03-07 09:37:29 -0500228 DeviceCM* fTopLayer;
229 SkConservativeClip fRasterClip;
230 SkMatrix fMatrix;
231 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232
Mike Reeda1361362017-03-07 09:37:29 -0500233 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700234 fLayer = nullptr;
235 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800236 fMatrix.reset();
237 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700238
reedd9544982014-09-09 18:46:22 -0700239 // don't bother initializing fNext
240 inc_rec();
241 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400242 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700243 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700244 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800245 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700246
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 // don't bother initializing fNext
248 inc_rec();
249 }
250 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700251 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 dec_rec();
253 }
mtkleinfeaadee2015-04-08 11:25:48 -0700254
255 void reset(const SkIRect& bounds) {
256 SkASSERT(fLayer);
257 SkASSERT(fDeferredSaveCount == 0);
258
259 fMatrix.reset();
260 fRasterClip.setRect(bounds);
261 fLayer->reset(bounds);
262 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263};
264
Mike Reeda1361362017-03-07 09:37:29 -0500265class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266public:
Mike Reeda1361362017-03-07 09:37:29 -0500267 SkDrawIter(SkCanvas* canvas)
268 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
269 {}
reed@google.com4b226022011-01-11 18:32:13 +0000270
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000272 const DeviceCM* rec = fCurrLayer;
273 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400274 fDevice = rec->fDevice.get();
275 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700277 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 return true;
279 }
280 return false;
281 }
reed@google.com4b226022011-01-11 18:32:13 +0000282
reed@google.com6f8f2922011-03-04 22:27:10 +0000283 int getX() const { return fDevice->getOrigin().x(); }
284 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000286
Mike Reed99330ba2017-02-22 11:01:08 -0500287 SkBaseDevice* fDevice;
288
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 const DeviceCM* fCurrLayer;
291 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292};
293
Florin Malita713b8ef2017-04-28 10:57:24 -0400294#define FOR_EACH_TOP_DEVICE( code ) \
295 do { \
296 DeviceCM* layer = fMCRec->fTopLayer; \
297 while (layer) { \
298 SkBaseDevice* device = layer->fDevice.get(); \
299 if (device) { \
300 code; \
301 } \
302 layer = layer->fNext; \
303 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500304 } while (0)
305
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306/////////////////////////////////////////////////////////////////////////////
307
reeddbc3cef2015-04-29 12:18:57 -0700308static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
309 return lazy->isValid() ? lazy->get() : lazy->set(orig);
310}
311
312/**
313 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700314 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700315 */
reedd053ce92016-03-22 10:17:23 -0700316static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700317 SkImageFilter* imgf = paint.getImageFilter();
318 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700319 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700320 }
321
reedd053ce92016-03-22 10:17:23 -0700322 SkColorFilter* imgCFPtr;
323 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700324 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700325 }
reedd053ce92016-03-22 10:17:23 -0700326 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700327
328 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700329 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700330 // there is no existing paint colorfilter, so we can just return the imagefilter's
331 return imgCF;
332 }
333
334 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
335 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500336 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700337}
338
senorblanco87e066e2015-10-28 11:23:36 -0700339/**
340 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
341 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
342 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
343 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
344 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
345 * conservative "effective" bounds based on the settings in the paint... with one exception. This
346 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
347 * deliberately ignored.
348 */
349static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
350 const SkRect& rawBounds,
351 SkRect* storage) {
352 SkPaint tmpUnfiltered(paint);
353 tmpUnfiltered.setImageFilter(nullptr);
354 if (tmpUnfiltered.canComputeFastBounds()) {
355 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
356 } else {
357 return rawBounds;
358 }
359}
360
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361class AutoDrawLooper {
362public:
senorblanco87e066e2015-10-28 11:23:36 -0700363 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
364 // paint. It's used to determine the size of the offscreen layer for filters.
365 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700366 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700367 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000368 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700369 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000370 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700371 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000372 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373
reedd053ce92016-03-22 10:17:23 -0700374 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700375 if (simplifiedCF) {
376 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700377 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700378 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700379 fPaint = paint;
380 }
381
382 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700383 /**
384 * We implement ImageFilters for a given draw by creating a layer, then applying the
385 * imagefilter to the pixels of that layer (its backing surface/image), and then
386 * we call restore() to xfer that layer to the main canvas.
387 *
388 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
389 * 2. Generate the src pixels:
390 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
391 * return (fPaint). We then draw the primitive (using srcover) into a cleared
392 * buffer/surface.
393 * 3. Restore the layer created in #1
394 * The imagefilter is passed the buffer/surface from the layer (now filled with the
395 * src pixels of the primitive). It returns a new "filtered" buffer, which we
396 * draw onto the previous layer using the xfermode from the original paint.
397 */
reed@google.com8926b162012-03-23 15:36:36 +0000398 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500399 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700400 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700401 SkRect storage;
402 if (rawBounds) {
403 // Make rawBounds include all paint outsets except for those due to image filters.
404 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
405 }
reedbfd5f172016-01-07 11:28:08 -0800406 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700407 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700408 fTempLayerForImageFilter = true;
409 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000410 }
411
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000412 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500413 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000414 fIsSimple = false;
415 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700416 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000417 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400418 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000419 }
420 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000421
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700423 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000424 fCanvas->internalRestore();
425 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000426 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000428
reed@google.com4e2b3d32011-04-07 14:18:59 +0000429 const SkPaint& paint() const {
430 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400431 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000432 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000434
Ben Wagner2c312c42018-06-27 14:46:46 -0400435 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000436 if (fDone) {
437 return false;
438 } else if (fIsSimple) {
439 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000440 return !fPaint->nothingToDraw();
441 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400442 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000443 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000444 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000445
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500447 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700448 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000449 SkCanvas* fCanvas;
450 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000451 const SkPaint* fPaint;
452 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700453 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000454 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000455 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000456 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400457 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000458
Ben Wagner2c312c42018-06-27 14:46:46 -0400459 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460};
461
Ben Wagner2c312c42018-06-27 14:46:46 -0400462bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700463 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000464 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400465 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000466
reeddbc3cef2015-04-29 12:18:57 -0700467 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
468 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400469 // never want our downstream clients (i.e. devices) to see loopers
470 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000471
reed5c476fb2015-04-20 08:04:21 -0700472 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700473 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700474 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000475 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000476
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000477 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000478 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000479 return false;
480 }
reed@google.com129ec222012-05-15 13:24:09 +0000481 fPaint = paint;
482
483 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400484 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000485 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000486 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000487 return true;
488}
489
reed@android.com8a1c16f2008-12-17 15:59:43 +0000490////////// macros to place around the internal draw calls //////////////////
491
reed3aafe112016-08-18 12:45:34 -0700492#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
493 this->predrawNotify(); \
494 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400495 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800496 SkDrawIter iter(this);
497
498
Ben Wagner2c312c42018-06-27 14:46:46 -0400499#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000500 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700501 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400502 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000503 SkDrawIter iter(this);
504
Ben Wagner2c312c42018-06-27 14:46:46 -0400505#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000506 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700507 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400508 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000510
Ben Wagner2c312c42018-06-27 14:46:46 -0400511#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700512 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700513 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400514 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700515 SkDrawIter iter(this);
516
reed@google.com4e2b3d32011-04-07 14:18:59 +0000517#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000518
519////////////////////////////////////////////////////////////////////////////
520
msarettfbfa2582016-08-12 08:29:08 -0700521static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
522 if (bounds.isEmpty()) {
523 return SkRect::MakeEmpty();
524 }
525
526 // Expand bounds out by 1 in case we are anti-aliasing. We store the
527 // bounds as floats to enable a faster quick reject implementation.
528 SkRect dst;
529 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
530 return dst;
531}
532
mtkleinfeaadee2015-04-08 11:25:48 -0700533void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
534 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700535 fMCRec->reset(bounds);
536
537 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500538 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400539 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700540 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700541 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700542}
543
Hal Canary363a3f82018-10-04 11:04:48 -0400544void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000545 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800546 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700547 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000548
549 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500550 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500551 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700552 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553
reeda499f902015-05-01 09:34:31 -0700554 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
555 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400556 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700557
reed@android.com8a1c16f2008-12-17 15:59:43 +0000558 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000559
halcanary96fcdcc2015-08-27 07:41:13 -0700560 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000561
reedf92c8662014-08-18 08:02:43 -0700562 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700563 // The root device and the canvas should always have the same pixel geometry
564 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800565 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700566 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500567
Mike Reedc42a1cd2017-02-14 14:25:14 -0500568 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700569 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400570
Herb Derby59d997a2018-06-07 12:44:09 -0400571 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000572}
573
reed@google.comcde92112011-07-06 20:00:52 +0000574SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000575 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700576 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000577{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000578 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000579
Hal Canary363a3f82018-10-04 11:04:48 -0400580 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000581}
582
reed96a857e2015-01-25 10:33:58 -0800583SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000584 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800585 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000586{
587 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400588 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400589 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700590}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000591
Hal Canary363a3f82018-10-04 11:04:48 -0400592SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700593 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700594 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700595{
596 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700597
Mike Reed566e53c2017-03-10 10:49:45 -0500598 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400599 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700600}
601
Herb Derbyefe39bc2018-05-01 17:06:20 -0400602SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000603 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700604 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000605{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000606 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700607
Hal Canary363a3f82018-10-04 11:04:48 -0400608 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700609}
610
reed4a8126e2014-09-22 07:29:03 -0700611SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700612 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700613 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700614{
615 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700616
Mike Reed910ca0f2018-04-25 13:04:05 -0400617 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400618 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700619}
reed29c857d2014-09-21 10:25:07 -0700620
Mike Reed356f7c22017-01-10 11:58:39 -0500621SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
622 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700623 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
624 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500625 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700626{
627 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700628
Mike Reed910ca0f2018-04-25 13:04:05 -0400629 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400630 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000631}
632
Mike Reed356f7c22017-01-10 11:58:39 -0500633SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
634
Matt Sarett31f99ce2017-04-11 08:46:01 -0400635#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
636SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
637 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
638 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
639 , fAllocator(nullptr)
640{
641 inc_canvas();
642
643 SkBitmap tmp(bitmap);
644 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400645 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400646 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400647}
648#endif
649
reed@android.com8a1c16f2008-12-17 15:59:43 +0000650SkCanvas::~SkCanvas() {
651 // free up the contents of our deque
652 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000653
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654 this->internalRestore(); // restore the last, since we're going away
655
halcanary385fe4d2015-08-26 13:07:48 -0700656 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000657
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658 dec_canvas();
659}
660
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000661SkMetaData& SkCanvas::getMetaData() {
662 // metadata users are rare, so we lazily allocate it. If that changes we
663 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700664 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000665 fMetaData = new SkMetaData;
666 }
667 return *fMetaData;
668}
669
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670///////////////////////////////////////////////////////////////////////////////
671
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000672void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700673 this->onFlush();
674}
675
676void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000677 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000678 if (device) {
679 device->flush();
680 }
681}
682
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000683SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000684 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000685 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
686}
687
senorblancoafc7cce2016-02-02 18:44:15 -0800688SkIRect SkCanvas::getTopLayerBounds() const {
689 SkBaseDevice* d = this->getTopDevice();
690 if (!d) {
691 return SkIRect::MakeEmpty();
692 }
693 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
694}
695
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000696SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000698 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400700 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000701}
702
Florin Malita0ed3b642017-01-13 16:56:38 +0000703SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400704 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000705}
706
Mike Reed353196f2017-07-21 11:01:18 -0400707bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000708 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400709 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000710}
711
Mike Reed353196f2017-07-21 11:01:18 -0400712bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
713 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400714}
715
716bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
717 SkPixmap pm;
718 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
719}
720
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000721bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400722 SkPixmap pm;
723 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700724 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000725 }
726 return false;
727}
728
Matt Sarett03dd6d52017-01-23 12:15:09 -0500729bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000730 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000731 SkBaseDevice* device = this->getDevice();
732 if (!device) {
733 return false;
734 }
735
Matt Sarett03dd6d52017-01-23 12:15:09 -0500736 // This check gives us an early out and prevents generation ID churn on the surface.
737 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
738 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
739 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
740 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000741 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000742
Matt Sarett03dd6d52017-01-23 12:15:09 -0500743 // Tell our owning surface to bump its generation ID.
744 const bool completeOverwrite =
745 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700746 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700747
Matt Sarett03dd6d52017-01-23 12:15:09 -0500748 // This can still fail, most notably in the case of a invalid color type or alpha type
749 // conversion. We could pull those checks into this function and avoid the unnecessary
750 // generation ID bump. But then we would be performing those checks twice, since they
751 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400752 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000753}
reed@google.com51df9e32010-12-23 19:29:18 +0000754
reed@android.com8a1c16f2008-12-17 15:59:43 +0000755//////////////////////////////////////////////////////////////////////////////
756
reed2ff1fce2014-12-11 07:07:37 -0800757void SkCanvas::checkForDeferredSave() {
758 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800759 this->doSave();
760 }
761}
762
reedf0090cb2014-11-26 08:55:51 -0800763int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800764#ifdef SK_DEBUG
765 int count = 0;
766 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
767 for (;;) {
768 const MCRec* rec = (const MCRec*)iter.next();
769 if (!rec) {
770 break;
771 }
772 count += 1 + rec->fDeferredSaveCount;
773 }
774 SkASSERT(count == fSaveCount);
775#endif
776 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800777}
778
779int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800780 fSaveCount += 1;
781 fMCRec->fDeferredSaveCount += 1;
782 return this->getSaveCount() - 1; // return our prev value
783}
784
785void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800786 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700787
788 SkASSERT(fMCRec->fDeferredSaveCount > 0);
789 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800790 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800791}
792
793void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800794 if (fMCRec->fDeferredSaveCount > 0) {
795 SkASSERT(fSaveCount > 1);
796 fSaveCount -= 1;
797 fMCRec->fDeferredSaveCount -= 1;
798 } else {
799 // check for underflow
800 if (fMCStack.count() > 1) {
801 this->willRestore();
802 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700803 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800804 this->internalRestore();
805 this->didRestore();
806 }
reedf0090cb2014-11-26 08:55:51 -0800807 }
808}
809
810void SkCanvas::restoreToCount(int count) {
811 // sanity check
812 if (count < 1) {
813 count = 1;
814 }
mtkleinf0f14112014-12-12 08:46:25 -0800815
reedf0090cb2014-11-26 08:55:51 -0800816 int n = this->getSaveCount() - count;
817 for (int i = 0; i < n; ++i) {
818 this->restore();
819 }
820}
821
reed2ff1fce2014-12-11 07:07:37 -0800822void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700824 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000826
Mike Reedc42a1cd2017-02-14 14:25:14 -0500827 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828}
829
reed4960eee2015-12-18 07:09:18 -0800830bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400831 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000832}
833
reed4960eee2015-12-18 07:09:18 -0800834bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700835 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500836 SkIRect clipBounds = this->getDeviceClipBounds();
837 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000838 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000839 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000840
reed96e657d2015-03-10 17:30:07 -0700841 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
842
Robert Phillips12078432018-05-17 11:17:39 -0400843 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
844 // If the image filter DAG affects transparent black then we will need to render
845 // out to the clip bounds
846 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000847 }
Robert Phillips12078432018-05-17 11:17:39 -0400848
849 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700850 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700852 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400853 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000854 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400855 inputSaveLayerBounds = clipBounds;
856 }
857
858 if (imageFilter) {
859 // expand the clip bounds by the image filter DAG to include extra content that might
860 // be required by the image filters.
861 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
862 SkImageFilter::kReverse_MapDirection,
863 &inputSaveLayerBounds);
864 }
865
866 SkIRect clippedSaveLayerBounds;
867 if (bounds) {
868 // For better or for worse, user bounds currently act as a hard clip on the layer's
869 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
870 clippedSaveLayerBounds = inputSaveLayerBounds;
871 } else {
872 // If there are no user bounds, we don't want to artificially restrict the resulting
873 // layer bounds, so allow the expanded clip bounds free reign.
874 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000875 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800876
877 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400878 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800879 if (BoundsAffectsClip(saveLayerFlags)) {
880 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
881 fMCRec->fRasterClip.setEmpty();
882 fDeviceClipBounds.setEmpty();
883 }
884 return false;
885 }
Robert Phillips12078432018-05-17 11:17:39 -0400886 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000887
reed4960eee2015-12-18 07:09:18 -0800888 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700889 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400890 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
891 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000892 }
893
894 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400895 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000896 }
Robert Phillips12078432018-05-17 11:17:39 -0400897
junov@chromium.orga907ac32012-02-24 21:54:07 +0000898 return true;
899}
900
reed4960eee2015-12-18 07:09:18 -0800901int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
902 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000903}
904
reed70ee31b2015-12-10 13:44:45 -0800905int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800906 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
907}
908
Cary Clarke041e312018-03-06 13:00:52 -0500909int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700910 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400911 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
912 // no need for the layer (or any of the draws until the matching restore()
913 this->save();
914 this->clipRect({0,0,0,0});
915 } else {
916 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
917 fSaveCount += 1;
918 this->internalSaveLayer(rec, strategy);
919 }
reed4960eee2015-12-18 07:09:18 -0800920 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800921}
922
reeda2217ef2016-07-20 06:04:34 -0700923void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500924 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500925 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700926 SkDraw draw;
927 SkRasterClip rc;
928 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
929 if (!dst->accessPixels(&draw.fDst)) {
930 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800931 }
reeda2217ef2016-07-20 06:04:34 -0700932 draw.fMatrix = &SkMatrix::I();
933 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800934
935 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500936 if (filter) {
937 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
938 }
reeda2217ef2016-07-20 06:04:34 -0700939
Mike Reedc42a1cd2017-02-14 14:25:14 -0500940 int x = src->getOrigin().x() - dstOrigin.x();
941 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700942 auto special = src->snapSpecial();
943 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400944 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700945 }
robertphillips7354a4b2015-12-16 05:08:27 -0800946}
reed70ee31b2015-12-10 13:44:45 -0800947
Mike Kleine083f7c2018-02-07 12:54:27 -0500948static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500949 // Need to force L32 for now if we have an image filter.
950 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
951 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500952 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800953 }
Mike Klein649fb732018-02-26 15:09:16 -0500954
955 SkColorType ct = prev.colorType();
956 if (prev.bytesPerPixel() <= 4) {
957 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
958 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
959 ct = kN32_SkColorType;
960 }
961 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800962}
963
reed4960eee2015-12-18 07:09:18 -0800964void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700965 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800966 const SkRect* bounds = rec.fBounds;
967 const SkPaint* paint = rec.fPaint;
968 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
969
reed8c30a812016-04-20 16:36:51 -0700970 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400971 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700972 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400973 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700974 SkMatrix remainder;
975 SkSize scale;
976 /*
977 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
978 * but they do handle scaling. To accommodate this, we do the following:
979 *
980 * 1. Stash off the current CTM
981 * 2. Decompose the CTM into SCALE and REMAINDER
982 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
983 * contains the REMAINDER
984 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
985 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
986 * of the original imagefilter, and draw that (via drawSprite)
987 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
988 *
989 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
990 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
991 */
reed96a04f32016-04-25 09:25:15 -0700992 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -0700993 stashedMatrix.decomposeScale(&scale, &remainder))
994 {
995 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -0400996 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -0700997 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
998 SkPaint* p = lazyP.set(*paint);
999 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1000 SkFilterQuality::kLow_SkFilterQuality,
1001 sk_ref_sp(imageFilter)));
1002 imageFilter = p->getImageFilter();
1003 paint = p;
1004 }
reed8c30a812016-04-20 16:36:51 -07001005
junov@chromium.orga907ac32012-02-24 21:54:07 +00001006 // do this before we create the layer. We don't call the public save() since
1007 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001008 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001009
junov@chromium.orga907ac32012-02-24 21:54:07 +00001010 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001011 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001012 if (modifiedRec) {
1013 // In this case there will be no layer in which to stash the matrix so we need to
1014 // revert the prior MCRec to its earlier state.
1015 modifiedRec->fMatrix = stashedMatrix;
1016 }
reed2ff1fce2014-12-11 07:07:37 -08001017 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001018 }
1019
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001020 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1021 // the clipRectBounds() call above?
1022 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001023 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001024 }
1025
reed8dc0ccb2015-03-20 06:32:52 -07001026 SkPixelGeometry geo = fProps.pixelGeometry();
1027 if (paint) {
reed76033be2015-03-14 10:54:31 -07001028 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001029 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001030 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001031 }
1032 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001033
robertphillips5139e502016-07-19 05:10:40 -07001034 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001035 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001036 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001037 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001038 }
reedb2db8982014-11-13 12:41:02 -08001039
Mike Kleine083f7c2018-02-07 12:54:27 -05001040 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001041
Hal Canary704cd322016-11-07 14:13:52 -05001042 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001043 {
reed70ee31b2015-12-10 13:44:45 -08001044 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001045 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001046 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001047 const bool trackCoverage =
1048 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001049 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001050 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001051 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001052 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001053 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1054 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001055 return;
reed61f501f2015-04-29 08:34:00 -07001056 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001057 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001058 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059
Mike Reedb43a3e02017-02-11 10:18:58 -05001060 // only have a "next" if this new layer doesn't affect the clip (rare)
1061 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062 fMCRec->fLayer = layer;
1063 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001064
Mike Reedc61abee2017-02-28 17:45:27 -05001065 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001066 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001067 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001068 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001069
Mike Reedc42a1cd2017-02-14 14:25:14 -05001070 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1071
1072 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1073 if (layer->fNext) {
1074 // need to punch a hole in the previous device, so we don't draw there, given that
1075 // the new top-layer will allow drawing to happen "below" it.
1076 SkRegion hole(ir);
1077 do {
1078 layer = layer->fNext;
1079 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1080 } while (layer->fNext);
1081 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001082}
1083
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001084int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001085 if (0xFF == alpha) {
1086 return this->saveLayer(bounds, nullptr);
1087 } else {
1088 SkPaint tmpPaint;
1089 tmpPaint.setAlpha(alpha);
1090 return this->saveLayer(bounds, &tmpPaint);
1091 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001092}
1093
reed@android.com8a1c16f2008-12-17 15:59:43 +00001094void SkCanvas::internalRestore() {
1095 SkASSERT(fMCStack.count() != 0);
1096
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001097 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098 DeviceCM* layer = fMCRec->fLayer; // may be null
1099 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001100 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101
1102 // now do the normal restore()
1103 fMCRec->~MCRec(); // balanced in save()
1104 fMCStack.pop_back();
1105 fMCRec = (MCRec*)fMCStack.back();
1106
Mike Reedc42a1cd2017-02-14 14:25:14 -05001107 if (fMCRec) {
1108 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1109 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001110
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1112 since if we're being recorded, we don't want to record this (the
1113 recorder will have already recorded the restore).
1114 */
bsalomon49f085d2014-09-05 13:34:00 -07001115 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001116 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001117 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001118 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001119 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001120 layer->fPaint.get(),
1121 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001122 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001123 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001124 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001125 delete layer;
reedb679ca82015-04-07 04:40:48 -07001126 } else {
1127 // we're at the root
reeda499f902015-05-01 09:34:31 -07001128 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001129 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001130 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001131 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001132 }
msarettfbfa2582016-08-12 08:29:08 -07001133
1134 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001135 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001136 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1137 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001138}
1139
reede8f30622016-03-23 18:59:25 -07001140sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001141 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001142 props = &fProps;
1143 }
1144 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001145}
1146
reede8f30622016-03-23 18:59:25 -07001147sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001148 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001149 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001150}
1151
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001152SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001153 return this->onImageInfo();
1154}
1155
1156SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001157 SkBaseDevice* dev = this->getDevice();
1158 if (dev) {
1159 return dev->imageInfo();
1160 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001161 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001162 }
1163}
1164
brianosman898235c2016-04-06 07:38:23 -07001165bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001166 return this->onGetProps(props);
1167}
1168
1169bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001170 SkBaseDevice* dev = this->getDevice();
1171 if (dev) {
1172 if (props) {
1173 *props = fProps;
1174 }
1175 return true;
1176 } else {
1177 return false;
1178 }
1179}
1180
reed6ceeebd2016-03-09 14:26:26 -08001181bool SkCanvas::peekPixels(SkPixmap* pmap) {
1182 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001183}
1184
reed884e97c2015-05-26 11:31:54 -07001185bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001186 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001187 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001188}
1189
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001190void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001191 SkPixmap pmap;
1192 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001193 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001194 }
1195 if (info) {
1196 *info = pmap.info();
1197 }
1198 if (rowBytes) {
1199 *rowBytes = pmap.rowBytes();
1200 }
1201 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001202 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001203 }
reed884e97c2015-05-26 11:31:54 -07001204 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001205}
1206
reed884e97c2015-05-26 11:31:54 -07001207bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001208 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001209 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001210}
1211
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001213
Florin Malita53f77bd2017-04-28 13:48:37 -04001214void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1215 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001217 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218 paint = &tmp;
1219 }
reed@google.com4b226022011-01-11 18:32:13 +00001220
Ben Wagner2c312c42018-06-27 14:46:46 -04001221 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001222
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001224 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001225 paint = &looper.paint();
1226 SkImageFilter* filter = paint->getImageFilter();
1227 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001228 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001229 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1230 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001231 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1232 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001233 }
reed@google.com76dd2772012-01-05 21:15:07 +00001234 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001235 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001236 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001237 }
reeda2217ef2016-07-20 06:04:34 -07001238
reed@google.com4e2b3d32011-04-07 14:18:59 +00001239 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240}
1241
reed32704672015-12-16 08:27:10 -08001242/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001243
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001244void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001245 if (dx || dy) {
1246 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001247 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001248
reedfe69b502016-09-12 06:31:48 -07001249 // Translate shouldn't affect the is-scale-translateness of the matrix.
1250 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001251
Mike Reedc42a1cd2017-02-14 14:25:14 -05001252 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001253
reedfe69b502016-09-12 06:31:48 -07001254 this->didTranslate(dx,dy);
1255 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001256}
1257
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001258void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001259 SkMatrix m;
1260 m.setScale(sx, sy);
1261 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001262}
1263
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001264void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001265 SkMatrix m;
1266 m.setRotate(degrees);
1267 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001268}
1269
bungeman7438bfc2016-07-12 15:01:19 -07001270void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1271 SkMatrix m;
1272 m.setRotate(degrees, px, py);
1273 this->concat(m);
1274}
1275
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001276void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001277 SkMatrix m;
1278 m.setSkew(sx, sy);
1279 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001280}
1281
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001282void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001283 if (matrix.isIdentity()) {
1284 return;
1285 }
1286
reed2ff1fce2014-12-11 07:07:37 -08001287 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001288 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001289 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001290
Mike Reed7627fa52017-02-08 10:07:53 -05001291 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001292
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001293 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001294}
1295
reed8c30a812016-04-20 16:36:51 -07001296void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001297 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001298 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001299
Mike Reedc42a1cd2017-02-14 14:25:14 -05001300 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001301}
1302
1303void SkCanvas::setMatrix(const SkMatrix& matrix) {
1304 this->checkForDeferredSave();
1305 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001306 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001307}
1308
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001310 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311}
1312
1313//////////////////////////////////////////////////////////////////////////////
1314
Mike Reedc1f77742016-12-09 09:00:50 -05001315void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001316 if (!rect.isFinite()) {
1317 return;
1318 }
reed2ff1fce2014-12-11 07:07:37 -08001319 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001320 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1321 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001322}
1323
Mike Reedc1f77742016-12-09 09:00:50 -05001324void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001325 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001326
Mike Reed7627fa52017-02-08 10:07:53 -05001327 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001328
reedc64eff52015-11-21 12:39:45 -08001329 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001330 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1331 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001332 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333}
1334
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001335void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1336 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001337 if (fClipRestrictionRect.isEmpty()) {
1338 // we notify the device, but we *dont* resolve deferred saves (since we're just
1339 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001340 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001341 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001342 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001343 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001344 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001345 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001346 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1347 }
1348}
1349
Mike Reedc1f77742016-12-09 09:00:50 -05001350void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001351 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001352 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001353 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001354 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1355 } else {
1356 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001357 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001358}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001359
Mike Reedc1f77742016-12-09 09:00:50 -05001360void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001361 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001362
Brian Salomona3b45d42016-10-03 11:36:16 -04001363 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001364
Mike Reed7627fa52017-02-08 10:07:53 -05001365 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001366
Mike Reed20800c82017-11-15 16:09:04 -05001367 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1368 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001369 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001370}
1371
Mike Reedc1f77742016-12-09 09:00:50 -05001372void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001373 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001374 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001375
1376 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1377 SkRect r;
1378 if (path.isRect(&r)) {
1379 this->onClipRect(r, op, edgeStyle);
1380 return;
1381 }
1382 SkRRect rrect;
1383 if (path.isOval(&r)) {
1384 rrect.setOval(r);
1385 this->onClipRRect(rrect, op, edgeStyle);
1386 return;
1387 }
1388 if (path.isRRect(&rrect)) {
1389 this->onClipRRect(rrect, op, edgeStyle);
1390 return;
1391 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001392 }
robertphillips39f05382015-11-24 09:30:12 -08001393
1394 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001395}
1396
Mike Reedc1f77742016-12-09 09:00:50 -05001397void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001398 AutoValidateClip avc(this);
1399
Brian Salomona3b45d42016-10-03 11:36:16 -04001400 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001401
Mike Reed7627fa52017-02-08 10:07:53 -05001402 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001403
Brian Salomona3b45d42016-10-03 11:36:16 -04001404 const SkPath* rasterClipPath = &path;
1405 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001406 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1407 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001408 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409}
1410
Mike Reedc1f77742016-12-09 09:00:50 -05001411void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001412 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001413 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001414}
1415
Mike Reedc1f77742016-12-09 09:00:50 -05001416void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001417 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001418
reed@google.com5c3d1472011-02-22 19:12:23 +00001419 AutoValidateClip avc(this);
1420
Mike Reed20800c82017-11-15 16:09:04 -05001421 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001422 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423}
1424
reed@google.com819c9212011-02-23 18:56:55 +00001425#ifdef SK_DEBUG
1426void SkCanvas::validateClip() const {
1427 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001428 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001429 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001430 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001431 return;
1432 }
reed@google.com819c9212011-02-23 18:56:55 +00001433}
1434#endif
1435
Mike Reeda1361362017-03-07 09:37:29 -05001436bool SkCanvas::androidFramework_isClipAA() const {
1437 bool containsAA = false;
1438
1439 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1440
1441 return containsAA;
1442}
1443
1444class RgnAccumulator {
1445 SkRegion* fRgn;
1446public:
1447 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1448 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1449 SkIPoint origin = device->getOrigin();
1450 if (origin.x() | origin.y()) {
1451 rgn->translate(origin.x(), origin.y());
1452 }
1453 fRgn->op(*rgn, SkRegion::kUnion_Op);
1454 }
1455};
1456
1457void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1458 RgnAccumulator accum(rgn);
1459 SkRegion tmp;
1460
1461 rgn->setEmpty();
1462 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001463}
1464
reed@google.com5c3d1472011-02-22 19:12:23 +00001465///////////////////////////////////////////////////////////////////////////////
1466
reed@google.com754de5f2014-02-24 19:38:20 +00001467bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001468 return fMCRec->fRasterClip.isEmpty();
1469
1470 // TODO: should we only use the conservative answer in a recording canvas?
1471#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001472 SkBaseDevice* dev = this->getTopDevice();
1473 // if no device we return true
1474 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001475#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001476}
1477
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001478bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001479 SkBaseDevice* dev = this->getTopDevice();
1480 // if no device we return false
1481 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001482}
1483
msarettfbfa2582016-08-12 08:29:08 -07001484static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1485#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1486 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1487 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1488 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1489 return 0xF != _mm_movemask_ps(mask);
1490#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1491 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1492 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1493 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1494 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1495#else
1496 SkRect devRectAsRect;
1497 SkRect devClipAsRect;
1498 devRect.store(&devRectAsRect.fLeft);
1499 devClip.store(&devClipAsRect.fLeft);
1500 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1501#endif
1502}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001503
msarettfbfa2582016-08-12 08:29:08 -07001504// It's important for this function to not be inlined. Otherwise the compiler will share code
1505// between the fast path and the slow path, resulting in two slow paths.
1506static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1507 const SkMatrix& matrix) {
1508 SkRect deviceRect;
1509 matrix.mapRect(&deviceRect, src);
1510 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1511}
1512
1513bool SkCanvas::quickReject(const SkRect& src) const {
1514#ifdef SK_DEBUG
1515 // Verify that fDeviceClipBounds are set properly.
1516 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001517 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001518 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001519 } else {
msarettfbfa2582016-08-12 08:29:08 -07001520 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001521 }
msarettfbfa2582016-08-12 08:29:08 -07001522
msarett9637ea92016-08-18 14:03:30 -07001523 // Verify that fIsScaleTranslate is set properly.
1524 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001525#endif
1526
msarett9637ea92016-08-18 14:03:30 -07001527 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001528 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1529 }
1530
1531 // We inline the implementation of mapScaleTranslate() for the fast path.
1532 float sx = fMCRec->fMatrix.getScaleX();
1533 float sy = fMCRec->fMatrix.getScaleY();
1534 float tx = fMCRec->fMatrix.getTranslateX();
1535 float ty = fMCRec->fMatrix.getTranslateY();
1536 Sk4f scale(sx, sy, sx, sy);
1537 Sk4f trans(tx, ty, tx, ty);
1538
1539 // Apply matrix.
1540 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1541
1542 // Make sure left < right, top < bottom.
1543 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1544 Sk4f min = Sk4f::Min(ltrb, rblt);
1545 Sk4f max = Sk4f::Max(ltrb, rblt);
1546 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1547 // ARM this sequence generates the fastest (a single instruction).
1548 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1549
1550 // Check if the device rect is NaN or outside the clip.
1551 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001552}
1553
reed@google.com3b3e8952012-08-16 20:53:31 +00001554bool SkCanvas::quickReject(const SkPath& path) const {
1555 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001556}
1557
Mike Klein83c8dd92017-11-28 17:08:45 -05001558SkRect SkCanvas::getLocalClipBounds() const {
1559 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001560 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001561 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001562 }
1563
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001564 SkMatrix inverse;
1565 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001566 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001567 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001568 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001569
Mike Reed42e8c532017-01-23 14:09:13 -05001570 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001571 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001572 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001573
Mike Reedb57b9312018-04-23 12:12:54 -04001574 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001575 inverse.mapRect(&bounds, r);
1576 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001577}
1578
Mike Klein83c8dd92017-11-28 17:08:45 -05001579SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001580 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001581}
1582
reed@android.com8a1c16f2008-12-17 15:59:43 +00001583const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001584 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001585}
1586
Brian Osman11052242016-10-27 14:47:55 -04001587GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001588 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001589 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001590}
1591
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001592GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001593 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001594 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001595}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001596
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001597void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1598 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001599 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001600 if (outer.isEmpty()) {
1601 return;
1602 }
1603 if (inner.isEmpty()) {
1604 this->drawRRect(outer, paint);
1605 return;
1606 }
1607
1608 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001609 // be able to return ...
1610 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001611 //
1612 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001613 if (!outer.getBounds().contains(inner.getBounds())) {
1614 return;
1615 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001616
1617 this->onDrawDRRect(outer, inner, paint);
1618}
1619
reed41af9662015-01-05 07:49:08 -08001620void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001621 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001622 this->onDrawPaint(paint);
1623}
1624
1625void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001626 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001627 // To avoid redundant logic in our culling code and various backends, we always sort rects
1628 // before passing them along.
1629 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001630}
1631
msarettdca352e2016-08-26 06:37:45 -07001632void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001633 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001634 if (region.isEmpty()) {
1635 return;
1636 }
1637
1638 if (region.isRect()) {
1639 return this->drawIRect(region.getBounds(), paint);
1640 }
1641
1642 this->onDrawRegion(region, paint);
1643}
1644
reed41af9662015-01-05 07:49:08 -08001645void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001646 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001647 // To avoid redundant logic in our culling code and various backends, we always sort rects
1648 // before passing them along.
1649 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001650}
1651
1652void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001653 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001654 this->onDrawRRect(rrect, paint);
1655}
1656
1657void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001658 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001659 this->onDrawPoints(mode, count, pts, paint);
1660}
1661
Mike Reede88a1cb2017-03-17 09:50:46 -04001662void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1663 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001664 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001665 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001666 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1667 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001668 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001669}
1670
1671void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001672 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001673 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001674 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1675}
1676
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001677void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1678 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001679 TRACE_EVENT0("skia", TRACE_FUNC);
1680 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001681 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001682 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1683}
1684
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001685void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1686 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001687 TRACE_EVENT0("skia", TRACE_FUNC);
1688 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001689 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001690 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001691}
1692
1693void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001694 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001695 this->onDrawPath(path, paint);
1696}
1697
reeda85d4d02015-05-06 12:56:48 -07001698void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001699 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001700 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001701 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001702}
1703
Mike Reedc4e31092018-01-30 11:15:27 -05001704// Returns true if the rect can be "filled" : non-empty and finite
1705static bool fillable(const SkRect& r) {
1706 SkScalar w = r.width();
1707 SkScalar h = r.height();
1708 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1709}
1710
reede47829b2015-08-06 10:02:53 -07001711void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1712 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001713 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001714 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001715 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001716 return;
1717 }
1718 this->onDrawImageRect(image, &src, dst, paint, constraint);
1719}
reed41af9662015-01-05 07:49:08 -08001720
reed84984ef2015-07-17 07:09:43 -07001721void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1722 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001723 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001724 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001725}
1726
reede47829b2015-08-06 10:02:53 -07001727void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1728 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001729 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001730 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1731 constraint);
1732}
reede47829b2015-08-06 10:02:53 -07001733
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001734namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001735class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001736public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001737 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1738 if (!origPaint) {
1739 return;
1740 }
1741 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1742 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1743 }
1744 if (origPaint->getMaskFilter()) {
1745 fPaint.writable()->setMaskFilter(nullptr);
1746 }
1747 if (origPaint->isAntiAlias()) {
1748 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001749 }
1750 }
1751
1752 const SkPaint* get() const {
1753 return fPaint;
1754 }
1755
1756private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001757 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001758};
1759} // namespace
1760
reed4c21dc52015-06-25 12:32:03 -07001761void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1762 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001763 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001764 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001765 if (dst.isEmpty()) {
1766 return;
1767 }
msarett552bca92016-08-03 06:53:26 -07001768 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001769 LatticePaint latticePaint(paint);
1770 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001771 } else {
reede47829b2015-08-06 10:02:53 -07001772 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001773 }
reed4c21dc52015-06-25 12:32:03 -07001774}
1775
msarett16882062016-08-16 09:31:08 -07001776void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1777 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001778 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001779 RETURN_ON_NULL(image);
1780 if (dst.isEmpty()) {
1781 return;
1782 }
msarett71df2d72016-09-30 12:41:42 -07001783
1784 SkIRect bounds;
1785 Lattice latticePlusBounds = lattice;
1786 if (!latticePlusBounds.fBounds) {
1787 bounds = SkIRect::MakeWH(image->width(), image->height());
1788 latticePlusBounds.fBounds = &bounds;
1789 }
1790
1791 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001792 LatticePaint latticePaint(paint);
1793 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001794 } else {
1795 this->drawImageRect(image, dst, paint);
1796 }
1797}
1798
Brian Salomond7065e72018-10-12 11:42:02 -04001799void SkCanvas::experimental_DrawImageSetV0(const ImageSetEntry imageSet[], int cnt, float alpha,
1800 SkFilterQuality filterQuality, SkBlendMode mode) {
1801 TRACE_EVENT0("skia", TRACE_FUNC);
1802 RETURN_ON_NULL(imageSet);
1803 RETURN_ON_FALSE(cnt);
1804
1805 this->onDrawImageSet(imageSet, cnt, alpha, filterQuality, mode);
1806}
1807
reed41af9662015-01-05 07:49:08 -08001808void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001809 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001810 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001811 return;
1812 }
reed41af9662015-01-05 07:49:08 -08001813 this->onDrawBitmap(bitmap, dx, dy, paint);
1814}
1815
reede47829b2015-08-06 10:02:53 -07001816void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001817 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001818 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001819 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001820 return;
1821 }
reede47829b2015-08-06 10:02:53 -07001822 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001823}
1824
reed84984ef2015-07-17 07:09:43 -07001825void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1826 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001827 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001828}
1829
reede47829b2015-08-06 10:02:53 -07001830void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1831 SrcRectConstraint constraint) {
1832 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1833 constraint);
1834}
reede47829b2015-08-06 10:02:53 -07001835
reed41af9662015-01-05 07:49:08 -08001836void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1837 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001838 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001839 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001840 return;
1841 }
msarett552bca92016-08-03 06:53:26 -07001842 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001843 LatticePaint latticePaint(paint);
1844 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001845 } else {
reeda5517e22015-07-14 10:54:12 -07001846 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001847 }
reed41af9662015-01-05 07:49:08 -08001848}
1849
msarettc573a402016-08-02 08:05:56 -07001850void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1851 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001852 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001853 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001854 return;
1855 }
msarett71df2d72016-09-30 12:41:42 -07001856
1857 SkIRect bounds;
1858 Lattice latticePlusBounds = lattice;
1859 if (!latticePlusBounds.fBounds) {
1860 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1861 latticePlusBounds.fBounds = &bounds;
1862 }
1863
1864 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001865 LatticePaint latticePaint(paint);
1866 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001867 } else {
msarett16882062016-08-16 09:31:08 -07001868 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001869 }
msarettc573a402016-08-02 08:05:56 -07001870}
1871
reed71c3c762015-06-24 10:29:17 -07001872void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001873 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001874 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001875 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001876 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001877 if (count <= 0) {
1878 return;
1879 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001880 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001881 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001882 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001883}
1884
reedf70b5312016-03-04 16:36:20 -08001885void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001886 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001887 if (key) {
1888 this->onDrawAnnotation(rect, key, value);
1889 }
1890}
1891
reede47829b2015-08-06 10:02:53 -07001892void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1893 const SkPaint* paint, SrcRectConstraint constraint) {
1894 if (src) {
1895 this->drawImageRect(image, *src, dst, paint, constraint);
1896 } else {
1897 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1898 dst, paint, constraint);
1899 }
1900}
1901void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1902 const SkPaint* paint, SrcRectConstraint constraint) {
1903 if (src) {
1904 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1905 } else {
1906 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1907 dst, paint, constraint);
1908 }
1909}
1910
Mike Reed4204da22017-05-17 08:53:36 -04001911void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001912 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001913 this->onDrawShadowRec(path, rec);
1914}
1915
1916void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1917 SkPaint paint;
1918 const SkRect& pathBounds = path.getBounds();
1919
Ben Wagner2c312c42018-06-27 14:46:46 -04001920 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001921 while (iter.next()) {
1922 iter.fDevice->drawShadow(path, rec);
1923 }
1924 LOOPER_END
1925}
1926
reed@android.com8a1c16f2008-12-17 15:59:43 +00001927//////////////////////////////////////////////////////////////////////////////
1928// These are the virtual drawing methods
1929//////////////////////////////////////////////////////////////////////////////
1930
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001931void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001932 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001933 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1934 }
1935}
1936
reed41af9662015-01-05 07:49:08 -08001937void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001938 this->internalDrawPaint(paint);
1939}
1940
1941void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04001942 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001943
1944 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001945 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001946 }
1947
reed@google.com4e2b3d32011-04-07 14:18:59 +00001948 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001949}
1950
reed41af9662015-01-05 07:49:08 -08001951void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1952 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001953 if ((long)count <= 0) {
1954 return;
1955 }
1956
Mike Reed822128b2017-02-28 16:41:03 -05001957 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001958 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001959 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001960 // special-case 2 points (common for drawing a single line)
1961 if (2 == count) {
1962 r.set(pts[0], pts[1]);
1963 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001964 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001965 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001966 if (!r.isFinite()) {
1967 return;
1968 }
Mike Reed822128b2017-02-28 16:41:03 -05001969 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001970 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1971 return;
1972 }
1973 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001974 }
reed@google.coma584aed2012-05-16 14:06:02 +00001975
halcanary96fcdcc2015-08-27 07:41:13 -07001976 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001977
Ben Wagner2c312c42018-06-27 14:46:46 -04001978 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001979
reed@android.com8a1c16f2008-12-17 15:59:43 +00001980 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001981 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001982 }
reed@google.com4b226022011-01-11 18:32:13 +00001983
reed@google.com4e2b3d32011-04-07 14:18:59 +00001984 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001985}
1986
reed4a167172016-08-18 17:15:25 -07001987static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1988 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07001989 (intptr_t)paint.getLooper() ) != 0;
1990}
1991
reed41af9662015-01-05 07:49:08 -08001992void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001993 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001994 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001995 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001996 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001997 return;
1998 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001999 }
reed@google.com4b226022011-01-11 18:32:13 +00002000
reed4a167172016-08-18 17:15:25 -07002001 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002002 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002003
reed4a167172016-08-18 17:15:25 -07002004 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002005 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002006 }
2007
2008 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002009 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002010 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002011 SkDrawIter iter(this);
2012 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002013 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002014 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002015 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002016}
2017
msarett44df6512016-08-25 13:54:30 -07002018void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002019 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002020 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002021 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002022 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2023 return;
2024 }
msarett44df6512016-08-25 13:54:30 -07002025 }
2026
Ben Wagner2c312c42018-06-27 14:46:46 -04002027 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002028
2029 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002030 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002031 }
2032
2033 LOOPER_END
2034}
2035
reed41af9662015-01-05 07:49:08 -08002036void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002037 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002038 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002039 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002040 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002041 return;
2042 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002043 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002044
Ben Wagner2c312c42018-06-27 14:46:46 -04002045 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002046
2047 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002048 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002049 }
2050
2051 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002052}
2053
bsalomonac3aa242016-08-19 11:25:19 -07002054void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2055 SkScalar sweepAngle, bool useCenter,
2056 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002057 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002058 if (paint.canComputeFastBounds()) {
2059 SkRect storage;
2060 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002061 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002062 return;
2063 }
bsalomonac3aa242016-08-19 11:25:19 -07002064 }
2065
Ben Wagner2c312c42018-06-27 14:46:46 -04002066 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002067
2068 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002069 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002070 }
2071
2072 LOOPER_END
2073}
2074
reed41af9662015-01-05 07:49:08 -08002075void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002076 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002077 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002078 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2079 return;
2080 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002081 }
2082
2083 if (rrect.isRect()) {
2084 // call the non-virtual version
2085 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002086 return;
2087 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002088 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002089 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2090 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002091 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002092
Ben Wagner2c312c42018-06-27 14:46:46 -04002093 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002094
2095 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002096 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002097 }
2098
2099 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002100}
2101
Mike Reed822128b2017-02-28 16:41:03 -05002102void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002103 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002104 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002105 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2106 return;
2107 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002108 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002109
Ben Wagner2c312c42018-06-27 14:46:46 -04002110 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002111
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002112 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002113 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002114 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002115
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002116 LOOPER_END
2117}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002118
reed41af9662015-01-05 07:49:08 -08002119void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002120 if (!path.isFinite()) {
2121 return;
2122 }
2123
Mike Reed822128b2017-02-28 16:41:03 -05002124 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002125 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002126 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002127 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2128 return;
2129 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002130 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002131
Mike Reed822128b2017-02-28 16:41:03 -05002132 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002133 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002134 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002135 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002136 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002137 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002138
Ben Wagner2c312c42018-06-27 14:46:46 -04002139 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002140
2141 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002142 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002143 }
2144
reed@google.com4e2b3d32011-04-07 14:18:59 +00002145 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002146}
2147
reed262a71b2015-12-05 13:07:27 -08002148bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002149 if (!paint.getImageFilter()) {
2150 return false;
2151 }
2152
2153 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002154 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002155 return false;
2156 }
2157
2158 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2159 // Once we can filter and the filter will return a result larger than itself, we should be
2160 // able to remove this constraint.
2161 // skbug.com/4526
2162 //
2163 SkPoint pt;
2164 ctm.mapXY(x, y, &pt);
2165 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2166 return ir.contains(fMCRec->fRasterClip.getBounds());
2167}
2168
Mike Reedf441cfc2018-04-11 14:50:16 -04002169// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2170// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2171// null.
2172static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2173 if (paintParam) {
2174 *real = *paintParam;
2175 real->setStyle(SkPaint::kFill_Style);
2176 real->setPathEffect(nullptr);
2177 paintParam = real;
2178 }
2179 return paintParam;
2180}
2181
reeda85d4d02015-05-06 12:56:48 -07002182void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002183 SkPaint realPaint;
2184 paint = init_image_paint(&realPaint, paint);
2185
reeda85d4d02015-05-06 12:56:48 -07002186 SkRect bounds = SkRect::MakeXYWH(x, y,
2187 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002188 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002189 SkRect tmp = bounds;
2190 if (paint) {
2191 paint->computeFastBounds(tmp, &tmp);
2192 }
2193 if (this->quickReject(tmp)) {
2194 return;
2195 }
reeda85d4d02015-05-06 12:56:48 -07002196 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002197 // At this point we need a real paint object. If the caller passed null, then we should
2198 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2199 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2200 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002201
reeda2217ef2016-07-20 06:04:34 -07002202 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002203 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2204 *paint);
2205 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002206 special = this->getDevice()->makeSpecial(image);
2207 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002208 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002209 }
2210 }
2211
reed262a71b2015-12-05 13:07:27 -08002212 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2213
reeda85d4d02015-05-06 12:56:48 -07002214 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002215 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002216 if (special) {
2217 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002218 iter.fDevice->ctm().mapXY(x, y, &pt);
2219 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002220 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002221 SkScalarRoundToInt(pt.fY), pnt,
2222 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002223 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002224 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002225 }
reeda85d4d02015-05-06 12:56:48 -07002226 }
halcanary9d524f22016-03-29 09:03:52 -07002227
reeda85d4d02015-05-06 12:56:48 -07002228 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002229}
2230
reed41af9662015-01-05 07:49:08 -08002231void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002232 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002233 SkPaint realPaint;
2234 paint = init_image_paint(&realPaint, paint);
2235
halcanary96fcdcc2015-08-27 07:41:13 -07002236 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002237 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002238 if (paint) {
2239 paint->computeFastBounds(dst, &storage);
2240 }
2241 if (this->quickReject(storage)) {
2242 return;
2243 }
reeda85d4d02015-05-06 12:56:48 -07002244 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002245 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002246
Ben Wagner2c312c42018-06-27 14:46:46 -04002247 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002248
reeda85d4d02015-05-06 12:56:48 -07002249 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002250 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002251 }
halcanary9d524f22016-03-29 09:03:52 -07002252
reeda85d4d02015-05-06 12:56:48 -07002253 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002254}
2255
reed41af9662015-01-05 07:49:08 -08002256void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002257 SkDEBUGCODE(bitmap.validate();)
2258
reed33366972015-10-08 09:22:02 -07002259 if (bitmap.drawsNothing()) {
2260 return;
2261 }
2262
Mike Reedf441cfc2018-04-11 14:50:16 -04002263 SkPaint realPaint;
2264 init_image_paint(&realPaint, paint);
2265 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002266
Mike Reed822128b2017-02-28 16:41:03 -05002267 SkRect bounds;
2268 bitmap.getBounds(&bounds);
2269 bounds.offset(x, y);
2270 bool canFastBounds = paint->canComputeFastBounds();
2271 if (canFastBounds) {
2272 SkRect storage;
2273 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002274 return;
2275 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002276 }
reed@google.com4b226022011-01-11 18:32:13 +00002277
reeda2217ef2016-07-20 06:04:34 -07002278 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002279 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2280 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002281 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002282 special = this->getDevice()->makeSpecial(bitmap);
2283 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002284 drawAsSprite = false;
2285 }
2286 }
2287
Mike Reed822128b2017-02-28 16:41:03 -05002288 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002289
2290 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002291 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002292 if (special) {
reed262a71b2015-12-05 13:07:27 -08002293 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002294 iter.fDevice->ctm().mapXY(x, y, &pt);
2295 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002296 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002297 SkScalarRoundToInt(pt.fY), pnt,
2298 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002299 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002300 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002301 }
reed33366972015-10-08 09:22:02 -07002302 }
msarettfbfa2582016-08-12 08:29:08 -07002303
reed33366972015-10-08 09:22:02 -07002304 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305}
2306
reed@google.com9987ec32011-09-07 11:57:52 +00002307// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002308void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002309 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002310 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002311 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002312 return;
2313 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002314
halcanary96fcdcc2015-08-27 07:41:13 -07002315 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002316 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002317 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2318 return;
2319 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002320 }
reed@google.com3d608122011-11-21 15:16:16 +00002321
reed@google.com33535f32012-09-25 15:37:50 +00002322 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002323 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002324 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002325 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002326
Ben Wagner2c312c42018-06-27 14:46:46 -04002327 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002328
reed@google.com33535f32012-09-25 15:37:50 +00002329 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002330 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002331 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002332
reed@google.com33535f32012-09-25 15:37:50 +00002333 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002334}
2335
reed41af9662015-01-05 07:49:08 -08002336void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002337 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002338 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002339 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002340}
2341
reed4c21dc52015-06-25 12:32:03 -07002342void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2343 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002344 SkPaint realPaint;
2345 paint = init_image_paint(&realPaint, paint);
2346
halcanary96fcdcc2015-08-27 07:41:13 -07002347 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002348 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002349 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2350 return;
2351 }
reed@google.com3d608122011-11-21 15:16:16 +00002352 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002353 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002354
Ben Wagner2c312c42018-06-27 14:46:46 -04002355 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002356
reed4c21dc52015-06-25 12:32:03 -07002357 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002358 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002359 }
halcanary9d524f22016-03-29 09:03:52 -07002360
reed4c21dc52015-06-25 12:32:03 -07002361 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002362}
2363
reed41af9662015-01-05 07:49:08 -08002364void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2365 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002366 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002367 SkPaint realPaint;
2368 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002369
halcanary96fcdcc2015-08-27 07:41:13 -07002370 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002371 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002372 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2373 return;
2374 }
reed4c21dc52015-06-25 12:32:03 -07002375 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002376 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002377
Ben Wagner2c312c42018-06-27 14:46:46 -04002378 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002379
reed4c21dc52015-06-25 12:32:03 -07002380 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002381 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002382 }
halcanary9d524f22016-03-29 09:03:52 -07002383
reed4c21dc52015-06-25 12:32:03 -07002384 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002385}
2386
msarett16882062016-08-16 09:31:08 -07002387void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2388 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002389 SkPaint realPaint;
2390 paint = init_image_paint(&realPaint, paint);
2391
msarett16882062016-08-16 09:31:08 -07002392 if (nullptr == paint || paint->canComputeFastBounds()) {
2393 SkRect storage;
2394 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2395 return;
2396 }
2397 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002398 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002399
Ben Wagner2c312c42018-06-27 14:46:46 -04002400 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002401
2402 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002403 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002404 }
2405
2406 LOOPER_END
2407}
2408
Brian Salomond7065e72018-10-12 11:42:02 -04002409void SkCanvas::onDrawImageSet(const ImageSetEntry imageSet[], int count, float alpha,
2410 SkFilterQuality filterQuality, SkBlendMode mode) {
2411 SkPaint paint;
2412 LOOPER_BEGIN(paint, nullptr);
2413 while (iter.next()) {
2414 iter.fDevice->drawImageSet(imageSet, count, alpha, filterQuality, mode);
2415 }
2416 LOOPER_END
2417}
2418
msarett16882062016-08-16 09:31:08 -07002419void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2420 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002421 SkPaint realPaint;
2422 paint = init_image_paint(&realPaint, paint);
2423
msarett16882062016-08-16 09:31:08 -07002424 if (nullptr == paint || paint->canComputeFastBounds()) {
2425 SkRect storage;
2426 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2427 return;
2428 }
2429 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002430 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002431
Ben Wagner2c312c42018-06-27 14:46:46 -04002432 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002433
2434 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002435 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002436 }
2437
2438 LOOPER_END
2439}
2440
reed@google.come0d9ce82014-04-23 04:00:17 +00002441void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2442 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002443
Ben Wagner2c312c42018-06-27 14:46:46 -04002444 LOOPER_BEGIN(paint, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002445
2446 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002447 fScratchGlyphRunBuilder->drawText(
Herb Derby4a447432018-06-22 11:45:27 -04002448 looper.paint(), text, byteLength, SkPoint::Make(x, y));
Herb Derby8a6348e2018-07-12 15:30:35 -04002449 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002450 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002451 }
2452
reed@google.com4e2b3d32011-04-07 14:18:59 +00002453 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002454}
2455
reed@google.come0d9ce82014-04-23 04:00:17 +00002456void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2457 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002458
Ben Wagner2c312c42018-06-27 14:46:46 -04002459 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002460
reed@android.com8a1c16f2008-12-17 15:59:43 +00002461 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002462 fScratchGlyphRunBuilder->drawPosText(looper.paint(), text, byteLength, pos);
Herb Derby8a6348e2018-07-12 15:30:35 -04002463 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002464 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002465 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002466
reed@google.com4e2b3d32011-04-07 14:18:59 +00002467 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002468}
2469
reed@google.come0d9ce82014-04-23 04:00:17 +00002470void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2471 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002472
Ben Wagner2c312c42018-06-27 14:46:46 -04002473 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002474
reed@android.com8a1c16f2008-12-17 15:59:43 +00002475 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002476 fScratchGlyphRunBuilder->drawPosTextH(
Herb Derby4a447432018-06-22 11:45:27 -04002477 looper.paint(), text, byteLength, xpos, constY);
Herb Derby8a6348e2018-07-12 15:30:35 -04002478 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002479 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002480 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002481
reed@google.com4e2b3d32011-04-07 14:18:59 +00002482 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002483}
2484
Herb Derby2eacff02018-07-18 13:41:15 -04002485void SkCanvas::onDrawTextRSXform(const void* text, size_t len, const SkRSXform xform[],
reed45561a02016-07-07 12:47:17 -07002486 const SkRect* cullRect, const SkPaint& paint) {
2487 if (cullRect && this->quickReject(*cullRect)) {
2488 return;
2489 }
2490
Ben Wagner2c312c42018-06-27 14:46:46 -04002491 LOOPER_BEGIN(paint, nullptr)
reed45561a02016-07-07 12:47:17 -07002492
2493 while (iter.next()) {
Herb Derby2eacff02018-07-18 13:41:15 -04002494 fScratchGlyphRunBuilder->drawTextAtOrigin(paint, text, len);
2495 auto list = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb935cf82018-07-26 16:54:18 -04002496 if (!list.empty()) {
2497 auto glyphRun = list[0];
Herb Derby2eacff02018-07-18 13:41:15 -04002498 iter.fDevice->drawGlyphRunRSXform(&glyphRun, xform);
2499 }
reed45561a02016-07-07 12:47:17 -07002500 }
2501
2502 LOOPER_END
2503}
2504
fmalita00d5c2c2014-08-21 08:53:26 -07002505void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2506 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002507 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002508 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002509 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002510 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002511 SkRect tmp;
2512 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2513 return;
2514 }
2515 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002516 }
2517
fmalita024f9962015-03-03 19:08:17 -08002518 // We cannot filter in the looper as we normally do, because the paint is
2519 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002520 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002521
fmalitaaa1b9122014-08-28 14:32:24 -07002522 while (iter.next()) {
Herb Derbyb983e6b2018-07-13 13:26:29 -04002523 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, SkPoint::Make(x, y));
2524 iter.fDevice->drawGlyphRunList(fScratchGlyphRunBuilder->useGlyphRunList());
fmalita00d5c2c2014-08-21 08:53:26 -07002525 }
2526
fmalitaaa1b9122014-08-28 14:32:24 -07002527 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002528}
2529
Cary Clark2a475ea2017-04-28 15:35:12 -04002530void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2531 this->drawText(string.c_str(), string.size(), x, y, paint);
2532}
2533
reed@google.come0d9ce82014-04-23 04:00:17 +00002534// These will become non-virtual, so they always call the (virtual) onDraw... method
2535void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2536 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002537 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002538 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002539 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002540 this->onDrawText(text, byteLength, x, y, paint);
2541 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002542}
2543void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2544 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002545 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002546 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002547 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002548 this->onDrawPosText(text, byteLength, pos, paint);
2549 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002550}
2551void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2552 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002553 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002554 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002555 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002556 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2557 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002558}
Mike Reed7c8d2e92018-08-27 16:38:05 -04002559
reed45561a02016-07-07 12:47:17 -07002560void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2561 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002562 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002563 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002564 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002565 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2566 }
2567}
fmalita00d5c2c2014-08-21 08:53:26 -07002568void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2569 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002570 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002571 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002572 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002573 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002574}
reed@google.come0d9ce82014-04-23 04:00:17 +00002575
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002576void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002577 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002578 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002579
2580 while (iter.next()) {
2581 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002582 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002583 }
2584
2585 LOOPER_END
2586}
2587
dandovb3c9d1c2014-08-12 08:34:29 -07002588void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002589 const SkPoint texCoords[4], SkBlendMode bmode,
2590 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002591 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002592 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002593 return;
2594 }
mtklein6cfa73a2014-08-13 13:33:49 -07002595
Mike Reedfaba3712016-11-03 14:45:31 -04002596 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002597}
2598
2599void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002600 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002601 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002602 // Since a patch is always within the convex hull of the control points, we discard it when its
2603 // bounding rectangle is completely outside the current clip.
2604 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002605 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002606 if (this->quickReject(bounds)) {
2607 return;
2608 }
mtklein6cfa73a2014-08-13 13:33:49 -07002609
Ben Wagner2c312c42018-06-27 14:46:46 -04002610 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002611
dandovecfff212014-08-04 10:02:00 -07002612 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002613 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002614 }
mtklein6cfa73a2014-08-13 13:33:49 -07002615
dandovecfff212014-08-04 10:02:00 -07002616 LOOPER_END
2617}
2618
reeda8db7282015-07-07 10:22:31 -07002619void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002620#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002621 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002622#endif
reede3b38ce2016-01-08 09:18:44 -08002623 RETURN_ON_NULL(dr);
2624 if (x || y) {
2625 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2626 this->onDrawDrawable(dr, &matrix);
2627 } else {
2628 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002629 }
2630}
2631
reeda8db7282015-07-07 10:22:31 -07002632void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002633#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002634 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002635#endif
reede3b38ce2016-01-08 09:18:44 -08002636 RETURN_ON_NULL(dr);
2637 if (matrix && matrix->isIdentity()) {
2638 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002639 }
reede3b38ce2016-01-08 09:18:44 -08002640 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002641}
2642
2643void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002644 // drawable bounds are no longer reliable (e.g. android displaylist)
2645 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002646 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002647}
2648
reed71c3c762015-06-24 10:29:17 -07002649void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002650 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002651 const SkRect* cull, const SkPaint* paint) {
2652 if (cull && this->quickReject(*cull)) {
2653 return;
2654 }
2655
2656 SkPaint pnt;
2657 if (paint) {
2658 pnt = *paint;
2659 }
halcanary9d524f22016-03-29 09:03:52 -07002660
Ben Wagner2c312c42018-06-27 14:46:46 -04002661 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002662 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002663 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002664 }
2665 LOOPER_END
2666}
2667
reedf70b5312016-03-04 16:36:20 -08002668void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2669 SkASSERT(key);
2670
2671 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002672 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002673 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002674 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002675 }
2676 LOOPER_END
2677}
2678
reed@android.com8a1c16f2008-12-17 15:59:43 +00002679//////////////////////////////////////////////////////////////////////////////
2680// These methods are NOT virtual, and therefore must call back into virtual
2681// methods, rather than actually drawing themselves.
2682//////////////////////////////////////////////////////////////////////////////
2683
reed374772b2016-10-05 17:33:02 -07002684void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002685 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002686 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002687 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002688 this->drawPaint(paint);
2689}
2690
2691void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002692 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002693 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2694}
2695
Mike Reed3661bc92017-02-22 13:21:42 -05002696void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002698 pts[0].set(x0, y0);
2699 pts[1].set(x1, y1);
2700 this->drawPoints(kLines_PointMode, 2, pts, paint);
2701}
2702
Mike Reed3661bc92017-02-22 13:21:42 -05002703void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002704 if (radius < 0) {
2705 radius = 0;
2706 }
2707
2708 SkRect r;
2709 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002710 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711}
2712
2713void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2714 const SkPaint& paint) {
2715 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002716 SkRRect rrect;
2717 rrect.setRectXY(r, rx, ry);
2718 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002719 } else {
2720 this->drawRect(r, paint);
2721 }
2722}
2723
reed@android.com8a1c16f2008-12-17 15:59:43 +00002724void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2725 SkScalar sweepAngle, bool useCenter,
2726 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002727 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002728 if (oval.isEmpty() || !sweepAngle) {
2729 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730 }
bsalomon21af9ca2016-08-25 12:29:23 -07002731 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002732}
2733
reed@android.comf76bacf2009-05-13 14:00:33 +00002734///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002735#ifdef SK_DISABLE_SKPICTURE
2736void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002737
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002738
2739void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2740 const SkPaint* paint) {}
2741#else
Mike Klein88d90712018-01-27 17:30:04 +00002742/**
2743 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2744 * against the playback cost of recursing into the subpicture to get at its actual ops.
2745 *
2746 * For now we pick a conservatively small value, though measurement (and other heuristics like
2747 * the type of ops contained) may justify changing this value.
2748 */
2749#define kMaxPictureOpsToUnrollInsteadOfRef 1
2750
reedd5fa1a42014-08-09 11:08:05 -07002751void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002752 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002753 RETURN_ON_NULL(picture);
2754
reede3b38ce2016-01-08 09:18:44 -08002755 if (matrix && matrix->isIdentity()) {
2756 matrix = nullptr;
2757 }
Mike Klein88d90712018-01-27 17:30:04 +00002758 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2759 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2760 picture->playback(this);
2761 } else {
2762 this->onDrawPicture(picture, matrix, paint);
2763 }
reedd5fa1a42014-08-09 11:08:05 -07002764}
robertphillips9b14f262014-06-04 05:40:44 -07002765
reedd5fa1a42014-08-09 11:08:05 -07002766void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2767 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002768 if (!paint || paint->canComputeFastBounds()) {
2769 SkRect bounds = picture->cullRect();
2770 if (paint) {
2771 paint->computeFastBounds(bounds, &bounds);
2772 }
2773 if (matrix) {
2774 matrix->mapRect(&bounds);
2775 }
2776 if (this->quickReject(bounds)) {
2777 return;
2778 }
2779 }
2780
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002781 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002782 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002783}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002784#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002785
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786///////////////////////////////////////////////////////////////////////////////
2787///////////////////////////////////////////////////////////////////////////////
2788
reed3aafe112016-08-18 12:45:34 -07002789SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002790 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791
2792 SkASSERT(canvas);
2793
reed3aafe112016-08-18 12:45:34 -07002794 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795 fDone = !fImpl->next();
2796}
2797
2798SkCanvas::LayerIter::~LayerIter() {
2799 fImpl->~SkDrawIter();
2800}
2801
2802void SkCanvas::LayerIter::next() {
2803 fDone = !fImpl->next();
2804}
2805
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002806SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002807 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002808}
2809
2810const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002811 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002812}
2813
2814const SkPaint& SkCanvas::LayerIter::paint() const {
2815 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002816 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817 paint = &fDefaultPaint;
2818 }
2819 return *paint;
2820}
2821
Mike Reedca37f322018-03-08 13:22:16 -05002822SkIRect SkCanvas::LayerIter::clipBounds() const {
2823 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002824}
2825
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2827int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002828
2829///////////////////////////////////////////////////////////////////////////////
2830
Mike Reed5df49342016-11-12 08:06:55 -06002831std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002832 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002833 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002834 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002835 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002836
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002837 SkBitmap bitmap;
2838 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002839 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002840 }
Mike Reed12f77342017-11-08 11:19:52 -05002841
2842 return props ?
2843 skstd::make_unique<SkCanvas>(bitmap, *props) :
2844 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002845}
reedd5fa1a42014-08-09 11:08:05 -07002846
2847///////////////////////////////////////////////////////////////////////////////
2848
Florin Malitaee424ac2016-12-01 12:47:59 -05002849SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002850 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002851
Florin Malita439ace92016-12-02 12:05:41 -05002852SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002853 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002854
Herb Derbyefe39bc2018-05-01 17:06:20 -04002855SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002856 : INHERITED(device) {}
2857
Florin Malitaee424ac2016-12-01 12:47:59 -05002858SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2859 (void)this->INHERITED::getSaveLayerStrategy(rec);
2860 return kNoLayer_SaveLayerStrategy;
2861}
2862
2863///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002864
reed73603f32016-09-20 08:42:38 -07002865static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2866static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2867static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2868static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2869static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2870static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002871
2872///////////////////////////////////////////////////////////////////////////////////////////////////
2873
2874SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2875 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002876 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002877 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2878 SkIPoint origin = dev->getOrigin();
2879 SkMatrix ctm = this->getTotalMatrix();
2880 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2881
2882 SkIRect clip = fMCRec->fRasterClip.getBounds();
2883 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002884 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002885 clip.setEmpty();
2886 }
2887
2888 fAllocator->updateHandle(handle, ctm, clip);
2889 return handle;
2890 }
2891 return nullptr;
2892}
2893
2894static bool install(SkBitmap* bm, const SkImageInfo& info,
2895 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002896 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002897}
2898
2899SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2900 SkBitmap* bm) {
2901 SkRasterHandleAllocator::Rec rec;
2902 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2903 return nullptr;
2904 }
2905 return rec.fHandle;
2906}
2907
2908std::unique_ptr<SkCanvas>
2909SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2910 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04002911 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05002912 return nullptr;
2913 }
2914
2915 SkBitmap bm;
2916 Handle hndl;
2917
2918 if (rec) {
2919 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2920 } else {
2921 hndl = alloc->allocBitmap(info, &bm);
2922 }
2923 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2924}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002925
2926///////////////////////////////////////////////////////////////////////////////////////////////////
2927
2928