blob: 9566a34b437c6c06fe57aa10ddbe780a0995a382 [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
Herb Derbyefe39bc2018-05-01 17:06:20 -0400544void SkCanvas::init(sk_sp<SkBaseDevice> device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800545 if (device && device->forceConservativeRasterClip()) {
546 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
547 }
reed42b73eb2015-11-20 13:42:42 -0800548
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000549 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800550 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700551 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552
553 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500554 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500555 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700556 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000557
reeda499f902015-05-01 09:34:31 -0700558 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
559 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400560 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700561
reed@android.com8a1c16f2008-12-17 15:59:43 +0000562 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563
halcanary96fcdcc2015-08-27 07:41:13 -0700564 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000565
reedf92c8662014-08-18 08:02:43 -0700566 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700567 // The root device and the canvas should always have the same pixel geometry
568 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800569 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700570 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500571
Mike Reedc42a1cd2017-02-14 14:25:14 -0500572 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700573 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400574
Herb Derby59d997a2018-06-07 12:44:09 -0400575 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576}
577
reed@google.comcde92112011-07-06 20:00:52 +0000578SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000579 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700580 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000581{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000582 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000583
halcanary96fcdcc2015-08-27 07:41:13 -0700584 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000585}
586
reed96a857e2015-01-25 10:33:58 -0800587SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000588 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800589 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000590{
591 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400592 this->init(sk_make_sp<SkNoPixelsDevice>(
593 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps), kDefault_InitFlags);
reedd9544982014-09-09 18:46:22 -0700594}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000595
reed78e27682014-11-19 08:04:34 -0800596SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700597 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700598 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700599{
600 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700601
Mike Reed566e53c2017-03-10 10:49:45 -0500602 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400603 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps), flags);
reedd9544982014-09-09 18:46:22 -0700604}
605
Herb Derbyefe39bc2018-05-01 17:06:20 -0400606SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000607 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700608 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000609{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000610 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700611
reedd9544982014-09-09 18:46:22 -0700612 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000613}
614
Herb Derbyefe39bc2018-05-01 17:06:20 -0400615SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device, InitFlags flags)
robertphillipsfcf78292015-06-19 11:49:52 -0700616 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700617 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700618{
619 inc_canvas();
620
621 this->init(device, flags);
622}
623
reed4a8126e2014-09-22 07:29:03 -0700624SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700625 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700626 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700627{
628 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700629
Mike Reed910ca0f2018-04-25 13:04:05 -0400630 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400631 this->init(device, kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700632}
reed29c857d2014-09-21 10:25:07 -0700633
Mike Reed356f7c22017-01-10 11:58:39 -0500634SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
635 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700636 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
637 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500638 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700639{
640 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700641
Mike Reed910ca0f2018-04-25 13:04:05 -0400642 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400643 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644}
645
Mike Reed356f7c22017-01-10 11:58:39 -0500646SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
647
Matt Sarett31f99ce2017-04-11 08:46:01 -0400648#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
649SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
650 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
651 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
652 , fAllocator(nullptr)
653{
654 inc_canvas();
655
656 SkBitmap tmp(bitmap);
657 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400658 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400659 this->init(device, kDefault_InitFlags);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400660}
661#endif
662
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663SkCanvas::~SkCanvas() {
664 // free up the contents of our deque
665 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000666
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667 this->internalRestore(); // restore the last, since we're going away
668
halcanary385fe4d2015-08-26 13:07:48 -0700669 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000670
reed@android.com8a1c16f2008-12-17 15:59:43 +0000671 dec_canvas();
672}
673
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000674SkMetaData& SkCanvas::getMetaData() {
675 // metadata users are rare, so we lazily allocate it. If that changes we
676 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700677 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000678 fMetaData = new SkMetaData;
679 }
680 return *fMetaData;
681}
682
reed@android.com8a1c16f2008-12-17 15:59:43 +0000683///////////////////////////////////////////////////////////////////////////////
684
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000685void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700686 this->onFlush();
687}
688
689void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000690 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000691 if (device) {
692 device->flush();
693 }
694}
695
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000696SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000697 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000698 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
699}
700
senorblancoafc7cce2016-02-02 18:44:15 -0800701SkIRect SkCanvas::getTopLayerBounds() const {
702 SkBaseDevice* d = this->getTopDevice();
703 if (!d) {
704 return SkIRect::MakeEmpty();
705 }
706 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
707}
708
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000709SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000710 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000711 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000712 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400713 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000714}
715
Florin Malita0ed3b642017-01-13 16:56:38 +0000716SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400717 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000718}
719
Mike Reed353196f2017-07-21 11:01:18 -0400720bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000721 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400722 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000723}
724
Mike Reed353196f2017-07-21 11:01:18 -0400725bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
726 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400727}
728
729bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
730 SkPixmap pm;
731 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
732}
733
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000734bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400735 SkPixmap pm;
736 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700737 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000738 }
739 return false;
740}
741
Matt Sarett03dd6d52017-01-23 12:15:09 -0500742bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000743 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000744 SkBaseDevice* device = this->getDevice();
745 if (!device) {
746 return false;
747 }
748
Matt Sarett03dd6d52017-01-23 12:15:09 -0500749 // This check gives us an early out and prevents generation ID churn on the surface.
750 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
751 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
752 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
753 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000754 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000755
Matt Sarett03dd6d52017-01-23 12:15:09 -0500756 // Tell our owning surface to bump its generation ID.
757 const bool completeOverwrite =
758 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700759 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700760
Matt Sarett03dd6d52017-01-23 12:15:09 -0500761 // This can still fail, most notably in the case of a invalid color type or alpha type
762 // conversion. We could pull those checks into this function and avoid the unnecessary
763 // generation ID bump. But then we would be performing those checks twice, since they
764 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400765 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000766}
reed@google.com51df9e32010-12-23 19:29:18 +0000767
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768//////////////////////////////////////////////////////////////////////////////
769
reed2ff1fce2014-12-11 07:07:37 -0800770void SkCanvas::checkForDeferredSave() {
771 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800772 this->doSave();
773 }
774}
775
reedf0090cb2014-11-26 08:55:51 -0800776int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800777#ifdef SK_DEBUG
778 int count = 0;
779 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
780 for (;;) {
781 const MCRec* rec = (const MCRec*)iter.next();
782 if (!rec) {
783 break;
784 }
785 count += 1 + rec->fDeferredSaveCount;
786 }
787 SkASSERT(count == fSaveCount);
788#endif
789 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800790}
791
792int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800793 fSaveCount += 1;
794 fMCRec->fDeferredSaveCount += 1;
795 return this->getSaveCount() - 1; // return our prev value
796}
797
798void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800799 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700800
801 SkASSERT(fMCRec->fDeferredSaveCount > 0);
802 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800803 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800804}
805
806void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800807 if (fMCRec->fDeferredSaveCount > 0) {
808 SkASSERT(fSaveCount > 1);
809 fSaveCount -= 1;
810 fMCRec->fDeferredSaveCount -= 1;
811 } else {
812 // check for underflow
813 if (fMCStack.count() > 1) {
814 this->willRestore();
815 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700816 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800817 this->internalRestore();
818 this->didRestore();
819 }
reedf0090cb2014-11-26 08:55:51 -0800820 }
821}
822
823void SkCanvas::restoreToCount(int count) {
824 // sanity check
825 if (count < 1) {
826 count = 1;
827 }
mtkleinf0f14112014-12-12 08:46:25 -0800828
reedf0090cb2014-11-26 08:55:51 -0800829 int n = this->getSaveCount() - count;
830 for (int i = 0; i < n; ++i) {
831 this->restore();
832 }
833}
834
reed2ff1fce2014-12-11 07:07:37 -0800835void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700837 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000838 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000839
Mike Reedc42a1cd2017-02-14 14:25:14 -0500840 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000841}
842
reed4960eee2015-12-18 07:09:18 -0800843bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400844 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845}
846
reed4960eee2015-12-18 07:09:18 -0800847bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700848 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500849 SkIRect clipBounds = this->getDeviceClipBounds();
850 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000851 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000852 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000853
reed96e657d2015-03-10 17:30:07 -0700854 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
855
Robert Phillips12078432018-05-17 11:17:39 -0400856 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
857 // If the image filter DAG affects transparent black then we will need to render
858 // out to the clip bounds
859 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000860 }
Robert Phillips12078432018-05-17 11:17:39 -0400861
862 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700863 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000864 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700865 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400866 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400868 inputSaveLayerBounds = clipBounds;
869 }
870
871 if (imageFilter) {
872 // expand the clip bounds by the image filter DAG to include extra content that might
873 // be required by the image filters.
874 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
875 SkImageFilter::kReverse_MapDirection,
876 &inputSaveLayerBounds);
877 }
878
879 SkIRect clippedSaveLayerBounds;
880 if (bounds) {
881 // For better or for worse, user bounds currently act as a hard clip on the layer's
882 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
883 clippedSaveLayerBounds = inputSaveLayerBounds;
884 } else {
885 // If there are no user bounds, we don't want to artificially restrict the resulting
886 // layer bounds, so allow the expanded clip bounds free reign.
887 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000888 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800889
890 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400891 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800892 if (BoundsAffectsClip(saveLayerFlags)) {
893 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
894 fMCRec->fRasterClip.setEmpty();
895 fDeviceClipBounds.setEmpty();
896 }
897 return false;
898 }
Robert Phillips12078432018-05-17 11:17:39 -0400899 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000900
reed4960eee2015-12-18 07:09:18 -0800901 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700902 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400903 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
904 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000905 }
906
907 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400908 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000909 }
Robert Phillips12078432018-05-17 11:17:39 -0400910
junov@chromium.orga907ac32012-02-24 21:54:07 +0000911 return true;
912}
913
reed4960eee2015-12-18 07:09:18 -0800914int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
915 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000916}
917
reed70ee31b2015-12-10 13:44:45 -0800918int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800919 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
920}
921
Cary Clarke041e312018-03-06 13:00:52 -0500922int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700923 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400924 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
925 // no need for the layer (or any of the draws until the matching restore()
926 this->save();
927 this->clipRect({0,0,0,0});
928 } else {
929 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
930 fSaveCount += 1;
931 this->internalSaveLayer(rec, strategy);
932 }
reed4960eee2015-12-18 07:09:18 -0800933 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800934}
935
reeda2217ef2016-07-20 06:04:34 -0700936void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500937 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500938 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700939 SkDraw draw;
940 SkRasterClip rc;
941 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
942 if (!dst->accessPixels(&draw.fDst)) {
943 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800944 }
reeda2217ef2016-07-20 06:04:34 -0700945 draw.fMatrix = &SkMatrix::I();
946 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800947
948 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500949 if (filter) {
950 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
951 }
reeda2217ef2016-07-20 06:04:34 -0700952
Mike Reedc42a1cd2017-02-14 14:25:14 -0500953 int x = src->getOrigin().x() - dstOrigin.x();
954 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700955 auto special = src->snapSpecial();
956 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400957 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700958 }
robertphillips7354a4b2015-12-16 05:08:27 -0800959}
reed70ee31b2015-12-10 13:44:45 -0800960
Mike Kleine083f7c2018-02-07 12:54:27 -0500961static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500962 // Need to force L32 for now if we have an image filter.
963 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
964 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500965 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800966 }
Mike Klein649fb732018-02-26 15:09:16 -0500967
968 SkColorType ct = prev.colorType();
969 if (prev.bytesPerPixel() <= 4) {
970 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
971 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
972 ct = kN32_SkColorType;
973 }
974 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800975}
976
reed4960eee2015-12-18 07:09:18 -0800977void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700978 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800979 const SkRect* bounds = rec.fBounds;
980 const SkPaint* paint = rec.fPaint;
981 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
982
reed8c30a812016-04-20 16:36:51 -0700983 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400984 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700985 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400986 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700987 SkMatrix remainder;
988 SkSize scale;
989 /*
990 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
991 * but they do handle scaling. To accommodate this, we do the following:
992 *
993 * 1. Stash off the current CTM
994 * 2. Decompose the CTM into SCALE and REMAINDER
995 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
996 * contains the REMAINDER
997 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
998 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
999 * of the original imagefilter, and draw that (via drawSprite)
1000 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1001 *
1002 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1003 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1004 */
reed96a04f32016-04-25 09:25:15 -07001005 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001006 stashedMatrix.decomposeScale(&scale, &remainder))
1007 {
1008 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001009 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001010 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1011 SkPaint* p = lazyP.set(*paint);
1012 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1013 SkFilterQuality::kLow_SkFilterQuality,
1014 sk_ref_sp(imageFilter)));
1015 imageFilter = p->getImageFilter();
1016 paint = p;
1017 }
reed8c30a812016-04-20 16:36:51 -07001018
junov@chromium.orga907ac32012-02-24 21:54:07 +00001019 // do this before we create the layer. We don't call the public save() since
1020 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001021 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001022
junov@chromium.orga907ac32012-02-24 21:54:07 +00001023 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001024 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001025 if (modifiedRec) {
1026 // In this case there will be no layer in which to stash the matrix so we need to
1027 // revert the prior MCRec to its earlier state.
1028 modifiedRec->fMatrix = stashedMatrix;
1029 }
reed2ff1fce2014-12-11 07:07:37 -08001030 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001031 }
1032
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001033 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1034 // the clipRectBounds() call above?
1035 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001036 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001037 }
1038
reed8dc0ccb2015-03-20 06:32:52 -07001039 SkPixelGeometry geo = fProps.pixelGeometry();
1040 if (paint) {
reed76033be2015-03-14 10:54:31 -07001041 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001042 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001043 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001044 }
1045 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001046
robertphillips5139e502016-07-19 05:10:40 -07001047 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001048 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001049 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001050 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001051 }
reedb2db8982014-11-13 12:41:02 -08001052
Mike Kleine083f7c2018-02-07 12:54:27 -05001053 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001054
Hal Canary704cd322016-11-07 14:13:52 -05001055 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001056 {
reed70ee31b2015-12-10 13:44:45 -08001057 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001058 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001059 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001060 const bool trackCoverage =
1061 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001062 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001063 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001064 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001065 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001066 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1067 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001068 return;
reed61f501f2015-04-29 08:34:00 -07001069 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001070 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001071 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072
Mike Reedb43a3e02017-02-11 10:18:58 -05001073 // only have a "next" if this new layer doesn't affect the clip (rare)
1074 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001075 fMCRec->fLayer = layer;
1076 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001077
Mike Reedc61abee2017-02-28 17:45:27 -05001078 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001079 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001080 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001081 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001082
Mike Reedc42a1cd2017-02-14 14:25:14 -05001083 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1084
1085 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1086 if (layer->fNext) {
1087 // need to punch a hole in the previous device, so we don't draw there, given that
1088 // the new top-layer will allow drawing to happen "below" it.
1089 SkRegion hole(ir);
1090 do {
1091 layer = layer->fNext;
1092 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1093 } while (layer->fNext);
1094 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095}
1096
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001097int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001098 if (0xFF == alpha) {
1099 return this->saveLayer(bounds, nullptr);
1100 } else {
1101 SkPaint tmpPaint;
1102 tmpPaint.setAlpha(alpha);
1103 return this->saveLayer(bounds, &tmpPaint);
1104 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001105}
1106
reed@android.com8a1c16f2008-12-17 15:59:43 +00001107void SkCanvas::internalRestore() {
1108 SkASSERT(fMCStack.count() != 0);
1109
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001110 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111 DeviceCM* layer = fMCRec->fLayer; // may be null
1112 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001113 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001114
1115 // now do the normal restore()
1116 fMCRec->~MCRec(); // balanced in save()
1117 fMCStack.pop_back();
1118 fMCRec = (MCRec*)fMCStack.back();
1119
Mike Reedc42a1cd2017-02-14 14:25:14 -05001120 if (fMCRec) {
1121 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1122 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001123
reed@android.com8a1c16f2008-12-17 15:59:43 +00001124 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1125 since if we're being recorded, we don't want to record this (the
1126 recorder will have already recorded the restore).
1127 */
bsalomon49f085d2014-09-05 13:34:00 -07001128 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001129 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001130 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001131 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001132 layer->fPaint.get(),
1133 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001134 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001135 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001136 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001137 delete layer;
reedb679ca82015-04-07 04:40:48 -07001138 } else {
1139 // we're at the root
reeda499f902015-05-01 09:34:31 -07001140 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001141 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001142 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001143 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001144 }
msarettfbfa2582016-08-12 08:29:08 -07001145
1146 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001147 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001148 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1149 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001150}
1151
reede8f30622016-03-23 18:59:25 -07001152sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001153 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001154 props = &fProps;
1155 }
1156 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001157}
1158
reede8f30622016-03-23 18:59:25 -07001159sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001160 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001161 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001162}
1163
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001164SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001165 return this->onImageInfo();
1166}
1167
1168SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001169 SkBaseDevice* dev = this->getDevice();
1170 if (dev) {
1171 return dev->imageInfo();
1172 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001173 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001174 }
1175}
1176
brianosman898235c2016-04-06 07:38:23 -07001177bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001178 return this->onGetProps(props);
1179}
1180
1181bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001182 SkBaseDevice* dev = this->getDevice();
1183 if (dev) {
1184 if (props) {
1185 *props = fProps;
1186 }
1187 return true;
1188 } else {
1189 return false;
1190 }
1191}
1192
reed6ceeebd2016-03-09 14:26:26 -08001193bool SkCanvas::peekPixels(SkPixmap* pmap) {
1194 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001195}
1196
reed884e97c2015-05-26 11:31:54 -07001197bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001198 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001199 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001200}
1201
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001202void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001203 SkPixmap pmap;
1204 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001205 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001206 }
1207 if (info) {
1208 *info = pmap.info();
1209 }
1210 if (rowBytes) {
1211 *rowBytes = pmap.rowBytes();
1212 }
1213 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001214 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001215 }
reed884e97c2015-05-26 11:31:54 -07001216 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001217}
1218
reed884e97c2015-05-26 11:31:54 -07001219bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001220 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001221 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001222}
1223
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001225
Florin Malita53f77bd2017-04-28 13:48:37 -04001226void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1227 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001229 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230 paint = &tmp;
1231 }
reed@google.com4b226022011-01-11 18:32:13 +00001232
Ben Wagner2c312c42018-06-27 14:46:46 -04001233 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001234
reed@android.com8a1c16f2008-12-17 15:59:43 +00001235 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001236 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001237 paint = &looper.paint();
1238 SkImageFilter* filter = paint->getImageFilter();
1239 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001240 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001241 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1242 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001243 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1244 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001245 }
reed@google.com76dd2772012-01-05 21:15:07 +00001246 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001247 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001248 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249 }
reeda2217ef2016-07-20 06:04:34 -07001250
reed@google.com4e2b3d32011-04-07 14:18:59 +00001251 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001252}
1253
reed32704672015-12-16 08:27:10 -08001254/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001255
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001256void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001257 if (dx || dy) {
1258 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001259 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001260
reedfe69b502016-09-12 06:31:48 -07001261 // Translate shouldn't affect the is-scale-translateness of the matrix.
1262 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001263
Mike Reedc42a1cd2017-02-14 14:25:14 -05001264 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001265
reedfe69b502016-09-12 06:31:48 -07001266 this->didTranslate(dx,dy);
1267 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001268}
1269
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001270void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001271 SkMatrix m;
1272 m.setScale(sx, sy);
1273 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001274}
1275
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001276void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001277 SkMatrix m;
1278 m.setRotate(degrees);
1279 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001280}
1281
bungeman7438bfc2016-07-12 15:01:19 -07001282void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1283 SkMatrix m;
1284 m.setRotate(degrees, px, py);
1285 this->concat(m);
1286}
1287
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001288void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001289 SkMatrix m;
1290 m.setSkew(sx, sy);
1291 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001292}
1293
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001294void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001295 if (matrix.isIdentity()) {
1296 return;
1297 }
1298
reed2ff1fce2014-12-11 07:07:37 -08001299 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001300 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001301 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001302
Mike Reed7627fa52017-02-08 10:07:53 -05001303 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001304
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001305 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001306}
1307
reed8c30a812016-04-20 16:36:51 -07001308void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001309 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001310 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001311
Mike Reedc42a1cd2017-02-14 14:25:14 -05001312 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001313}
1314
1315void SkCanvas::setMatrix(const SkMatrix& matrix) {
1316 this->checkForDeferredSave();
1317 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001318 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319}
1320
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001322 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323}
1324
1325//////////////////////////////////////////////////////////////////////////////
1326
Mike Reedc1f77742016-12-09 09:00:50 -05001327void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001328 if (!rect.isFinite()) {
1329 return;
1330 }
reed2ff1fce2014-12-11 07:07:37 -08001331 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001332 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1333 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001334}
1335
Mike Reedc1f77742016-12-09 09:00:50 -05001336void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001337 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001338
Mike Reed7627fa52017-02-08 10:07:53 -05001339 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001340
reedc64eff52015-11-21 12:39:45 -08001341 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001342 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1343 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001344 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001345}
1346
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001347void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1348 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001349 if (fClipRestrictionRect.isEmpty()) {
1350 // we notify the device, but we *dont* resolve deferred saves (since we're just
1351 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001352 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001353 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001354 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001355 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001356 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001357 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001358 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1359 }
1360}
1361
Mike Reedc1f77742016-12-09 09:00:50 -05001362void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001363 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001364 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001365 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001366 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1367 } else {
1368 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001369 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001370}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001371
Mike Reedc1f77742016-12-09 09:00:50 -05001372void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001373 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001374
Brian Salomona3b45d42016-10-03 11:36:16 -04001375 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001376
Mike Reed7627fa52017-02-08 10:07:53 -05001377 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001378
Mike Reed20800c82017-11-15 16:09:04 -05001379 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1380 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001381 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001382}
1383
Mike Reedc1f77742016-12-09 09:00:50 -05001384void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001385 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001386 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001387
1388 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1389 SkRect r;
1390 if (path.isRect(&r)) {
1391 this->onClipRect(r, op, edgeStyle);
1392 return;
1393 }
1394 SkRRect rrect;
1395 if (path.isOval(&r)) {
1396 rrect.setOval(r);
1397 this->onClipRRect(rrect, op, edgeStyle);
1398 return;
1399 }
1400 if (path.isRRect(&rrect)) {
1401 this->onClipRRect(rrect, op, edgeStyle);
1402 return;
1403 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001404 }
robertphillips39f05382015-11-24 09:30:12 -08001405
1406 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001407}
1408
Mike Reedc1f77742016-12-09 09:00:50 -05001409void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001410 AutoValidateClip avc(this);
1411
Brian Salomona3b45d42016-10-03 11:36:16 -04001412 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001413
Mike Reed7627fa52017-02-08 10:07:53 -05001414 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415
Brian Salomona3b45d42016-10-03 11:36:16 -04001416 const SkPath* rasterClipPath = &path;
1417 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001418 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1419 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001420 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001421}
1422
Mike Reedc1f77742016-12-09 09:00:50 -05001423void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001424 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001425 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001426}
1427
Mike Reedc1f77742016-12-09 09:00:50 -05001428void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001429 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001430
reed@google.com5c3d1472011-02-22 19:12:23 +00001431 AutoValidateClip avc(this);
1432
Mike Reed20800c82017-11-15 16:09:04 -05001433 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001434 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001435}
1436
reed@google.com819c9212011-02-23 18:56:55 +00001437#ifdef SK_DEBUG
1438void SkCanvas::validateClip() const {
1439 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001440 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001441 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001442 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001443 return;
1444 }
reed@google.com819c9212011-02-23 18:56:55 +00001445}
1446#endif
1447
Mike Reeda1361362017-03-07 09:37:29 -05001448bool SkCanvas::androidFramework_isClipAA() const {
1449 bool containsAA = false;
1450
1451 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1452
1453 return containsAA;
1454}
1455
1456class RgnAccumulator {
1457 SkRegion* fRgn;
1458public:
1459 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1460 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1461 SkIPoint origin = device->getOrigin();
1462 if (origin.x() | origin.y()) {
1463 rgn->translate(origin.x(), origin.y());
1464 }
1465 fRgn->op(*rgn, SkRegion::kUnion_Op);
1466 }
1467};
1468
1469void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1470 RgnAccumulator accum(rgn);
1471 SkRegion tmp;
1472
1473 rgn->setEmpty();
1474 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001475}
1476
reed@google.com5c3d1472011-02-22 19:12:23 +00001477///////////////////////////////////////////////////////////////////////////////
1478
reed@google.com754de5f2014-02-24 19:38:20 +00001479bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001480 return fMCRec->fRasterClip.isEmpty();
1481
1482 // TODO: should we only use the conservative answer in a recording canvas?
1483#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001484 SkBaseDevice* dev = this->getTopDevice();
1485 // if no device we return true
1486 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001487#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001488}
1489
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001490bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001491 SkBaseDevice* dev = this->getTopDevice();
1492 // if no device we return false
1493 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001494}
1495
msarettfbfa2582016-08-12 08:29:08 -07001496static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1497#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1498 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1499 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1500 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1501 return 0xF != _mm_movemask_ps(mask);
1502#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1503 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1504 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1505 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1506 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1507#else
1508 SkRect devRectAsRect;
1509 SkRect devClipAsRect;
1510 devRect.store(&devRectAsRect.fLeft);
1511 devClip.store(&devClipAsRect.fLeft);
1512 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1513#endif
1514}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001515
msarettfbfa2582016-08-12 08:29:08 -07001516// It's important for this function to not be inlined. Otherwise the compiler will share code
1517// between the fast path and the slow path, resulting in two slow paths.
1518static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1519 const SkMatrix& matrix) {
1520 SkRect deviceRect;
1521 matrix.mapRect(&deviceRect, src);
1522 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1523}
1524
1525bool SkCanvas::quickReject(const SkRect& src) const {
1526#ifdef SK_DEBUG
1527 // Verify that fDeviceClipBounds are set properly.
1528 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001529 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001530 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001531 } else {
msarettfbfa2582016-08-12 08:29:08 -07001532 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001533 }
msarettfbfa2582016-08-12 08:29:08 -07001534
msarett9637ea92016-08-18 14:03:30 -07001535 // Verify that fIsScaleTranslate is set properly.
1536 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001537#endif
1538
msarett9637ea92016-08-18 14:03:30 -07001539 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001540 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1541 }
1542
1543 // We inline the implementation of mapScaleTranslate() for the fast path.
1544 float sx = fMCRec->fMatrix.getScaleX();
1545 float sy = fMCRec->fMatrix.getScaleY();
1546 float tx = fMCRec->fMatrix.getTranslateX();
1547 float ty = fMCRec->fMatrix.getTranslateY();
1548 Sk4f scale(sx, sy, sx, sy);
1549 Sk4f trans(tx, ty, tx, ty);
1550
1551 // Apply matrix.
1552 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1553
1554 // Make sure left < right, top < bottom.
1555 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1556 Sk4f min = Sk4f::Min(ltrb, rblt);
1557 Sk4f max = Sk4f::Max(ltrb, rblt);
1558 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1559 // ARM this sequence generates the fastest (a single instruction).
1560 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1561
1562 // Check if the device rect is NaN or outside the clip.
1563 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001564}
1565
reed@google.com3b3e8952012-08-16 20:53:31 +00001566bool SkCanvas::quickReject(const SkPath& path) const {
1567 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001568}
1569
Mike Klein83c8dd92017-11-28 17:08:45 -05001570SkRect SkCanvas::getLocalClipBounds() const {
1571 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001572 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001573 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001574 }
1575
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001576 SkMatrix inverse;
1577 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001578 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001579 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001580 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001581
Mike Reed42e8c532017-01-23 14:09:13 -05001582 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001583 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001584 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001585
Mike Reedb57b9312018-04-23 12:12:54 -04001586 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001587 inverse.mapRect(&bounds, r);
1588 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001589}
1590
Mike Klein83c8dd92017-11-28 17:08:45 -05001591SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001592 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001593}
1594
reed@android.com8a1c16f2008-12-17 15:59:43 +00001595const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001596 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001597}
1598
Brian Osman11052242016-10-27 14:47:55 -04001599GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001600 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001601 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001602}
1603
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001604GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001605 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001606 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001607}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001608
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001609void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1610 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001611 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001612 if (outer.isEmpty()) {
1613 return;
1614 }
1615 if (inner.isEmpty()) {
1616 this->drawRRect(outer, paint);
1617 return;
1618 }
1619
1620 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001621 // be able to return ...
1622 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001623 //
1624 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001625 if (!outer.getBounds().contains(inner.getBounds())) {
1626 return;
1627 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001628
1629 this->onDrawDRRect(outer, inner, paint);
1630}
1631
reed41af9662015-01-05 07:49:08 -08001632void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001633 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001634 this->onDrawPaint(paint);
1635}
1636
1637void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001638 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001639 // To avoid redundant logic in our culling code and various backends, we always sort rects
1640 // before passing them along.
1641 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001642}
1643
msarettdca352e2016-08-26 06:37:45 -07001644void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001645 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001646 if (region.isEmpty()) {
1647 return;
1648 }
1649
1650 if (region.isRect()) {
1651 return this->drawIRect(region.getBounds(), paint);
1652 }
1653
1654 this->onDrawRegion(region, paint);
1655}
1656
reed41af9662015-01-05 07:49:08 -08001657void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001658 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001659 // To avoid redundant logic in our culling code and various backends, we always sort rects
1660 // before passing them along.
1661 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001662}
1663
1664void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001665 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001666 this->onDrawRRect(rrect, paint);
1667}
1668
1669void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001670 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001671 this->onDrawPoints(mode, count, pts, paint);
1672}
1673
Mike Reede88a1cb2017-03-17 09:50:46 -04001674void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1675 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001676 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001677 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001678 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1679 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001680 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001681}
1682
1683void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001684 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001685 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001686 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1687}
1688
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001689void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1690 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001691 TRACE_EVENT0("skia", TRACE_FUNC);
1692 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001693 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001694 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1695}
1696
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001697void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1698 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001699 TRACE_EVENT0("skia", TRACE_FUNC);
1700 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001701 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001702 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001703}
1704
1705void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001706 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001707 this->onDrawPath(path, paint);
1708}
1709
reeda85d4d02015-05-06 12:56:48 -07001710void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001711 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001712 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001713 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001714}
1715
Mike Reedc4e31092018-01-30 11:15:27 -05001716// Returns true if the rect can be "filled" : non-empty and finite
1717static bool fillable(const SkRect& r) {
1718 SkScalar w = r.width();
1719 SkScalar h = r.height();
1720 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1721}
1722
reede47829b2015-08-06 10:02:53 -07001723void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1724 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001725 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001726 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001727 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001728 return;
1729 }
1730 this->onDrawImageRect(image, &src, dst, paint, constraint);
1731}
reed41af9662015-01-05 07:49:08 -08001732
reed84984ef2015-07-17 07:09:43 -07001733void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1734 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001735 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001736 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001737}
1738
reede47829b2015-08-06 10:02:53 -07001739void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1740 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001741 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001742 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1743 constraint);
1744}
reede47829b2015-08-06 10:02:53 -07001745
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001746namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001747class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001748public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001749 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1750 if (!origPaint) {
1751 return;
1752 }
1753 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1754 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1755 }
1756 if (origPaint->getMaskFilter()) {
1757 fPaint.writable()->setMaskFilter(nullptr);
1758 }
1759 if (origPaint->isAntiAlias()) {
1760 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001761 }
1762 }
1763
1764 const SkPaint* get() const {
1765 return fPaint;
1766 }
1767
1768private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001769 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001770};
1771} // namespace
1772
reed4c21dc52015-06-25 12:32:03 -07001773void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1774 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001775 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001776 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001777 if (dst.isEmpty()) {
1778 return;
1779 }
msarett552bca92016-08-03 06:53:26 -07001780 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001781 LatticePaint latticePaint(paint);
1782 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001783 } else {
reede47829b2015-08-06 10:02:53 -07001784 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001785 }
reed4c21dc52015-06-25 12:32:03 -07001786}
1787
msarett16882062016-08-16 09:31:08 -07001788void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1789 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001790 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001791 RETURN_ON_NULL(image);
1792 if (dst.isEmpty()) {
1793 return;
1794 }
msarett71df2d72016-09-30 12:41:42 -07001795
1796 SkIRect bounds;
1797 Lattice latticePlusBounds = lattice;
1798 if (!latticePlusBounds.fBounds) {
1799 bounds = SkIRect::MakeWH(image->width(), image->height());
1800 latticePlusBounds.fBounds = &bounds;
1801 }
1802
1803 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001804 LatticePaint latticePaint(paint);
1805 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001806 } else {
1807 this->drawImageRect(image, dst, paint);
1808 }
1809}
1810
reed41af9662015-01-05 07:49:08 -08001811void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001812 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001813 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001814 return;
1815 }
reed41af9662015-01-05 07:49:08 -08001816 this->onDrawBitmap(bitmap, dx, dy, paint);
1817}
1818
reede47829b2015-08-06 10:02:53 -07001819void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001820 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001821 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001822 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001823 return;
1824 }
reede47829b2015-08-06 10:02:53 -07001825 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001826}
1827
reed84984ef2015-07-17 07:09:43 -07001828void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1829 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001830 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001831}
1832
reede47829b2015-08-06 10:02:53 -07001833void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1834 SrcRectConstraint constraint) {
1835 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1836 constraint);
1837}
reede47829b2015-08-06 10:02:53 -07001838
reed41af9662015-01-05 07:49:08 -08001839void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1840 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001841 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001842 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001843 return;
1844 }
msarett552bca92016-08-03 06:53:26 -07001845 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001846 LatticePaint latticePaint(paint);
1847 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001848 } else {
reeda5517e22015-07-14 10:54:12 -07001849 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001850 }
reed41af9662015-01-05 07:49:08 -08001851}
1852
msarettc573a402016-08-02 08:05:56 -07001853void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1854 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001855 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001856 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001857 return;
1858 }
msarett71df2d72016-09-30 12:41:42 -07001859
1860 SkIRect bounds;
1861 Lattice latticePlusBounds = lattice;
1862 if (!latticePlusBounds.fBounds) {
1863 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1864 latticePlusBounds.fBounds = &bounds;
1865 }
1866
1867 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001868 LatticePaint latticePaint(paint);
1869 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001870 } else {
msarett16882062016-08-16 09:31:08 -07001871 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001872 }
msarettc573a402016-08-02 08:05:56 -07001873}
1874
reed71c3c762015-06-24 10:29:17 -07001875void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001876 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001877 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001878 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001879 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001880 if (count <= 0) {
1881 return;
1882 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001883 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001884 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001885 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001886}
1887
reedf70b5312016-03-04 16:36:20 -08001888void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001889 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001890 if (key) {
1891 this->onDrawAnnotation(rect, key, value);
1892 }
1893}
1894
reede47829b2015-08-06 10:02:53 -07001895void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1896 const SkPaint* paint, SrcRectConstraint constraint) {
1897 if (src) {
1898 this->drawImageRect(image, *src, dst, paint, constraint);
1899 } else {
1900 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1901 dst, paint, constraint);
1902 }
1903}
1904void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1905 const SkPaint* paint, SrcRectConstraint constraint) {
1906 if (src) {
1907 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1908 } else {
1909 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1910 dst, paint, constraint);
1911 }
1912}
1913
Mike Reed4204da22017-05-17 08:53:36 -04001914void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001915 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001916 this->onDrawShadowRec(path, rec);
1917}
1918
1919void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1920 SkPaint paint;
1921 const SkRect& pathBounds = path.getBounds();
1922
Ben Wagner2c312c42018-06-27 14:46:46 -04001923 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001924 while (iter.next()) {
1925 iter.fDevice->drawShadow(path, rec);
1926 }
1927 LOOPER_END
1928}
1929
reed@android.com8a1c16f2008-12-17 15:59:43 +00001930//////////////////////////////////////////////////////////////////////////////
1931// These are the virtual drawing methods
1932//////////////////////////////////////////////////////////////////////////////
1933
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001934void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001935 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001936 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1937 }
1938}
1939
reed41af9662015-01-05 07:49:08 -08001940void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001941 this->internalDrawPaint(paint);
1942}
1943
1944void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04001945 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001946
1947 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001948 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001949 }
1950
reed@google.com4e2b3d32011-04-07 14:18:59 +00001951 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001952}
1953
reed41af9662015-01-05 07:49:08 -08001954void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1955 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001956 if ((long)count <= 0) {
1957 return;
1958 }
1959
Mike Reed822128b2017-02-28 16:41:03 -05001960 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001961 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001962 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001963 // special-case 2 points (common for drawing a single line)
1964 if (2 == count) {
1965 r.set(pts[0], pts[1]);
1966 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001967 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001968 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001969 if (!r.isFinite()) {
1970 return;
1971 }
Mike Reed822128b2017-02-28 16:41:03 -05001972 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001973 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1974 return;
1975 }
1976 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001977 }
reed@google.coma584aed2012-05-16 14:06:02 +00001978
halcanary96fcdcc2015-08-27 07:41:13 -07001979 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001980
Ben Wagner2c312c42018-06-27 14:46:46 -04001981 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001982
reed@android.com8a1c16f2008-12-17 15:59:43 +00001983 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001984 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001985 }
reed@google.com4b226022011-01-11 18:32:13 +00001986
reed@google.com4e2b3d32011-04-07 14:18:59 +00001987 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001988}
1989
reed4a167172016-08-18 17:15:25 -07001990static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1991 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07001992 (intptr_t)paint.getLooper() ) != 0;
1993}
1994
reed41af9662015-01-05 07:49:08 -08001995void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001996 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001997 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001998 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001999 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002000 return;
2001 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002002 }
reed@google.com4b226022011-01-11 18:32:13 +00002003
reed4a167172016-08-18 17:15:25 -07002004 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002005 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002006
reed4a167172016-08-18 17:15:25 -07002007 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002008 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002009 }
2010
2011 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002012 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002013 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002014 SkDrawIter iter(this);
2015 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002016 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002017 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002018 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002019}
2020
msarett44df6512016-08-25 13:54:30 -07002021void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002022 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002023 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002024 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002025 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2026 return;
2027 }
msarett44df6512016-08-25 13:54:30 -07002028 }
2029
Ben Wagner2c312c42018-06-27 14:46:46 -04002030 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002031
2032 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002033 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002034 }
2035
2036 LOOPER_END
2037}
2038
reed41af9662015-01-05 07:49:08 -08002039void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002040 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002041 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002042 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002043 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002044 return;
2045 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002046 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002047
Ben Wagner2c312c42018-06-27 14:46:46 -04002048 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002049
2050 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002051 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002052 }
2053
2054 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002055}
2056
bsalomonac3aa242016-08-19 11:25:19 -07002057void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2058 SkScalar sweepAngle, bool useCenter,
2059 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002060 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002061 if (paint.canComputeFastBounds()) {
2062 SkRect storage;
2063 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002064 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002065 return;
2066 }
bsalomonac3aa242016-08-19 11:25:19 -07002067 }
2068
Ben Wagner2c312c42018-06-27 14:46:46 -04002069 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002070
2071 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002072 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002073 }
2074
2075 LOOPER_END
2076}
2077
reed41af9662015-01-05 07:49:08 -08002078void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002079 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002080 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002081 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2082 return;
2083 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002084 }
2085
2086 if (rrect.isRect()) {
2087 // call the non-virtual version
2088 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002089 return;
2090 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002091 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002092 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2093 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002094 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002095
Ben Wagner2c312c42018-06-27 14:46:46 -04002096 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002097
2098 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002099 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002100 }
2101
2102 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002103}
2104
Mike Reed822128b2017-02-28 16:41:03 -05002105void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002106 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002107 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002108 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2109 return;
2110 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002111 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002112
Ben Wagner2c312c42018-06-27 14:46:46 -04002113 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002114
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002115 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002116 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002117 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002118
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002119 LOOPER_END
2120}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002121
reed41af9662015-01-05 07:49:08 -08002122void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002123 if (!path.isFinite()) {
2124 return;
2125 }
2126
Mike Reed822128b2017-02-28 16:41:03 -05002127 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002128 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002129 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002130 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2131 return;
2132 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002133 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002134
Mike Reed822128b2017-02-28 16:41:03 -05002135 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002136 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002137 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002138 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002139 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002140 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002141
Ben Wagner2c312c42018-06-27 14:46:46 -04002142 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002143
2144 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002145 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002146 }
2147
reed@google.com4e2b3d32011-04-07 14:18:59 +00002148 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002149}
2150
reed262a71b2015-12-05 13:07:27 -08002151bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002152 if (!paint.getImageFilter()) {
2153 return false;
2154 }
2155
2156 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002157 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002158 return false;
2159 }
2160
2161 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2162 // Once we can filter and the filter will return a result larger than itself, we should be
2163 // able to remove this constraint.
2164 // skbug.com/4526
2165 //
2166 SkPoint pt;
2167 ctm.mapXY(x, y, &pt);
2168 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2169 return ir.contains(fMCRec->fRasterClip.getBounds());
2170}
2171
Mike Reedf441cfc2018-04-11 14:50:16 -04002172// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2173// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2174// null.
2175static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2176 if (paintParam) {
2177 *real = *paintParam;
2178 real->setStyle(SkPaint::kFill_Style);
2179 real->setPathEffect(nullptr);
2180 paintParam = real;
2181 }
2182 return paintParam;
2183}
2184
reeda85d4d02015-05-06 12:56:48 -07002185void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002186 SkPaint realPaint;
2187 paint = init_image_paint(&realPaint, paint);
2188
reeda85d4d02015-05-06 12:56:48 -07002189 SkRect bounds = SkRect::MakeXYWH(x, y,
2190 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002191 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002192 SkRect tmp = bounds;
2193 if (paint) {
2194 paint->computeFastBounds(tmp, &tmp);
2195 }
2196 if (this->quickReject(tmp)) {
2197 return;
2198 }
reeda85d4d02015-05-06 12:56:48 -07002199 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002200 // At this point we need a real paint object. If the caller passed null, then we should
2201 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2202 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2203 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002204
reeda2217ef2016-07-20 06:04:34 -07002205 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002206 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2207 *paint);
2208 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002209 special = this->getDevice()->makeSpecial(image);
2210 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002211 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002212 }
2213 }
2214
reed262a71b2015-12-05 13:07:27 -08002215 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2216
reeda85d4d02015-05-06 12:56:48 -07002217 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002218 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002219 if (special) {
2220 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002221 iter.fDevice->ctm().mapXY(x, y, &pt);
2222 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002223 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002224 SkScalarRoundToInt(pt.fY), pnt,
2225 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002226 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002227 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002228 }
reeda85d4d02015-05-06 12:56:48 -07002229 }
halcanary9d524f22016-03-29 09:03:52 -07002230
reeda85d4d02015-05-06 12:56:48 -07002231 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002232}
2233
reed41af9662015-01-05 07:49:08 -08002234void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002235 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002236 SkPaint realPaint;
2237 paint = init_image_paint(&realPaint, paint);
2238
halcanary96fcdcc2015-08-27 07:41:13 -07002239 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002240 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002241 if (paint) {
2242 paint->computeFastBounds(dst, &storage);
2243 }
2244 if (this->quickReject(storage)) {
2245 return;
2246 }
reeda85d4d02015-05-06 12:56:48 -07002247 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002248 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002249
Ben Wagner2c312c42018-06-27 14:46:46 -04002250 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002251
reeda85d4d02015-05-06 12:56:48 -07002252 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002253 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002254 }
halcanary9d524f22016-03-29 09:03:52 -07002255
reeda85d4d02015-05-06 12:56:48 -07002256 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002257}
2258
reed41af9662015-01-05 07:49:08 -08002259void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002260 SkDEBUGCODE(bitmap.validate();)
2261
reed33366972015-10-08 09:22:02 -07002262 if (bitmap.drawsNothing()) {
2263 return;
2264 }
2265
Mike Reedf441cfc2018-04-11 14:50:16 -04002266 SkPaint realPaint;
2267 init_image_paint(&realPaint, paint);
2268 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002269
Mike Reed822128b2017-02-28 16:41:03 -05002270 SkRect bounds;
2271 bitmap.getBounds(&bounds);
2272 bounds.offset(x, y);
2273 bool canFastBounds = paint->canComputeFastBounds();
2274 if (canFastBounds) {
2275 SkRect storage;
2276 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002277 return;
2278 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002279 }
reed@google.com4b226022011-01-11 18:32:13 +00002280
reeda2217ef2016-07-20 06:04:34 -07002281 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002282 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2283 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002284 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002285 special = this->getDevice()->makeSpecial(bitmap);
2286 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002287 drawAsSprite = false;
2288 }
2289 }
2290
Mike Reed822128b2017-02-28 16:41:03 -05002291 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002292
2293 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002294 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002295 if (special) {
reed262a71b2015-12-05 13:07:27 -08002296 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002297 iter.fDevice->ctm().mapXY(x, y, &pt);
2298 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002299 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002300 SkScalarRoundToInt(pt.fY), pnt,
2301 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002302 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002303 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002304 }
reed33366972015-10-08 09:22:02 -07002305 }
msarettfbfa2582016-08-12 08:29:08 -07002306
reed33366972015-10-08 09:22:02 -07002307 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308}
2309
reed@google.com9987ec32011-09-07 11:57:52 +00002310// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002311void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002312 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002313 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002314 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002315 return;
2316 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002317
halcanary96fcdcc2015-08-27 07:41:13 -07002318 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002319 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002320 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2321 return;
2322 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002323 }
reed@google.com3d608122011-11-21 15:16:16 +00002324
reed@google.com33535f32012-09-25 15:37:50 +00002325 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002326 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002327 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002328 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002329
Ben Wagner2c312c42018-06-27 14:46:46 -04002330 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002331
reed@google.com33535f32012-09-25 15:37:50 +00002332 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002333 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002334 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002335
reed@google.com33535f32012-09-25 15:37:50 +00002336 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002337}
2338
reed41af9662015-01-05 07:49:08 -08002339void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002340 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002341 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002342 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002343}
2344
reed4c21dc52015-06-25 12:32:03 -07002345void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2346 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002347 SkPaint realPaint;
2348 paint = init_image_paint(&realPaint, paint);
2349
halcanary96fcdcc2015-08-27 07:41:13 -07002350 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002351 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002352 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2353 return;
2354 }
reed@google.com3d608122011-11-21 15:16:16 +00002355 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002356 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002357
Ben Wagner2c312c42018-06-27 14:46:46 -04002358 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002359
reed4c21dc52015-06-25 12:32:03 -07002360 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002361 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002362 }
halcanary9d524f22016-03-29 09:03:52 -07002363
reed4c21dc52015-06-25 12:32:03 -07002364 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002365}
2366
reed41af9662015-01-05 07:49:08 -08002367void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2368 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002369 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002370 SkPaint realPaint;
2371 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002372
halcanary96fcdcc2015-08-27 07:41:13 -07002373 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002374 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002375 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2376 return;
2377 }
reed4c21dc52015-06-25 12:32:03 -07002378 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002379 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002380
Ben Wagner2c312c42018-06-27 14:46:46 -04002381 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002382
reed4c21dc52015-06-25 12:32:03 -07002383 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002384 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002385 }
halcanary9d524f22016-03-29 09:03:52 -07002386
reed4c21dc52015-06-25 12:32:03 -07002387 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002388}
2389
msarett16882062016-08-16 09:31:08 -07002390void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2391 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002392 SkPaint realPaint;
2393 paint = init_image_paint(&realPaint, paint);
2394
msarett16882062016-08-16 09:31:08 -07002395 if (nullptr == paint || paint->canComputeFastBounds()) {
2396 SkRect storage;
2397 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2398 return;
2399 }
2400 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002401 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002402
Ben Wagner2c312c42018-06-27 14:46:46 -04002403 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002404
2405 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002406 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002407 }
2408
2409 LOOPER_END
2410}
2411
2412void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2413 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002414 SkPaint realPaint;
2415 paint = init_image_paint(&realPaint, paint);
2416
msarett16882062016-08-16 09:31:08 -07002417 if (nullptr == paint || paint->canComputeFastBounds()) {
2418 SkRect storage;
2419 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2420 return;
2421 }
2422 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002423 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002424
Ben Wagner2c312c42018-06-27 14:46:46 -04002425 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002426
2427 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002428 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002429 }
2430
2431 LOOPER_END
2432}
2433
reed@google.come0d9ce82014-04-23 04:00:17 +00002434void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2435 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002436
Ben Wagner2c312c42018-06-27 14:46:46 -04002437 LOOPER_BEGIN(paint, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002438
2439 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002440 fScratchGlyphRunBuilder->drawText(
Herb Derby4a447432018-06-22 11:45:27 -04002441 looper.paint(), text, byteLength, SkPoint::Make(x, y));
Herb Derby8a6348e2018-07-12 15:30:35 -04002442 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002443 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002444 }
2445
reed@google.com4e2b3d32011-04-07 14:18:59 +00002446 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002447}
2448
reed@google.come0d9ce82014-04-23 04:00:17 +00002449void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2450 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002451
Ben Wagner2c312c42018-06-27 14:46:46 -04002452 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002453
reed@android.com8a1c16f2008-12-17 15:59:43 +00002454 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002455 fScratchGlyphRunBuilder->drawPosText(looper.paint(), text, byteLength, pos);
Herb Derby8a6348e2018-07-12 15:30:35 -04002456 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002457 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002458 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002459
reed@google.com4e2b3d32011-04-07 14:18:59 +00002460 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002461}
2462
reed@google.come0d9ce82014-04-23 04:00:17 +00002463void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2464 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002465
Ben Wagner2c312c42018-06-27 14:46:46 -04002466 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002467
reed@android.com8a1c16f2008-12-17 15:59:43 +00002468 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002469 fScratchGlyphRunBuilder->drawPosTextH(
Herb Derby4a447432018-06-22 11:45:27 -04002470 looper.paint(), text, byteLength, xpos, constY);
Herb Derby8a6348e2018-07-12 15:30:35 -04002471 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002472 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002474
reed@google.com4e2b3d32011-04-07 14:18:59 +00002475 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002476}
2477
Herb Derby2eacff02018-07-18 13:41:15 -04002478void SkCanvas::onDrawTextRSXform(const void* text, size_t len, const SkRSXform xform[],
reed45561a02016-07-07 12:47:17 -07002479 const SkRect* cullRect, const SkPaint& paint) {
2480 if (cullRect && this->quickReject(*cullRect)) {
2481 return;
2482 }
2483
Ben Wagner2c312c42018-06-27 14:46:46 -04002484 LOOPER_BEGIN(paint, nullptr)
reed45561a02016-07-07 12:47:17 -07002485
2486 while (iter.next()) {
Herb Derby2eacff02018-07-18 13:41:15 -04002487 fScratchGlyphRunBuilder->drawTextAtOrigin(paint, text, len);
2488 auto list = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb935cf82018-07-26 16:54:18 -04002489 if (!list.empty()) {
2490 auto glyphRun = list[0];
Herb Derby2eacff02018-07-18 13:41:15 -04002491 iter.fDevice->drawGlyphRunRSXform(&glyphRun, xform);
2492 }
reed45561a02016-07-07 12:47:17 -07002493 }
2494
2495 LOOPER_END
2496}
2497
fmalita00d5c2c2014-08-21 08:53:26 -07002498void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2499 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002500 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002501 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002502 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002503 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002504 SkRect tmp;
2505 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2506 return;
2507 }
2508 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002509 }
2510
fmalita024f9962015-03-03 19:08:17 -08002511 // We cannot filter in the looper as we normally do, because the paint is
2512 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002513 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002514
fmalitaaa1b9122014-08-28 14:32:24 -07002515 while (iter.next()) {
Herb Derbyb983e6b2018-07-13 13:26:29 -04002516 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, SkPoint::Make(x, y));
2517 iter.fDevice->drawGlyphRunList(fScratchGlyphRunBuilder->useGlyphRunList());
fmalita00d5c2c2014-08-21 08:53:26 -07002518 }
2519
fmalitaaa1b9122014-08-28 14:32:24 -07002520 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002521}
2522
Cary Clark2a475ea2017-04-28 15:35:12 -04002523void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2524 this->drawText(string.c_str(), string.size(), x, y, paint);
2525}
2526
reed@google.come0d9ce82014-04-23 04:00:17 +00002527// These will become non-virtual, so they always call the (virtual) onDraw... method
2528void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2529 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002530 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002531 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002532 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002533 this->onDrawText(text, byteLength, x, y, paint);
2534 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002535}
2536void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2537 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002538 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002539 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002540 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002541 this->onDrawPosText(text, byteLength, pos, paint);
2542 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002543}
2544void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2545 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002546 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002547 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002548 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002549 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2550 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002551}
Mike Reed7c8d2e92018-08-27 16:38:05 -04002552
reed45561a02016-07-07 12:47:17 -07002553void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2554 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002555 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002556 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002557 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002558 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2559 }
2560}
fmalita00d5c2c2014-08-21 08:53:26 -07002561void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2562 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002563 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002564 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002565 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002566 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002567}
reed@google.come0d9ce82014-04-23 04:00:17 +00002568
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002569void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002570 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002571 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002572
2573 while (iter.next()) {
2574 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002575 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002576 }
2577
2578 LOOPER_END
2579}
2580
dandovb3c9d1c2014-08-12 08:34:29 -07002581void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002582 const SkPoint texCoords[4], SkBlendMode bmode,
2583 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002584 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002585 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002586 return;
2587 }
mtklein6cfa73a2014-08-13 13:33:49 -07002588
Mike Reedfaba3712016-11-03 14:45:31 -04002589 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002590}
2591
2592void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002593 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002594 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002595 // Since a patch is always within the convex hull of the control points, we discard it when its
2596 // bounding rectangle is completely outside the current clip.
2597 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002598 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002599 if (this->quickReject(bounds)) {
2600 return;
2601 }
mtklein6cfa73a2014-08-13 13:33:49 -07002602
Ben Wagner2c312c42018-06-27 14:46:46 -04002603 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002604
dandovecfff212014-08-04 10:02:00 -07002605 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002606 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002607 }
mtklein6cfa73a2014-08-13 13:33:49 -07002608
dandovecfff212014-08-04 10:02:00 -07002609 LOOPER_END
2610}
2611
reeda8db7282015-07-07 10:22:31 -07002612void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002613#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002614 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002615#endif
reede3b38ce2016-01-08 09:18:44 -08002616 RETURN_ON_NULL(dr);
2617 if (x || y) {
2618 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2619 this->onDrawDrawable(dr, &matrix);
2620 } else {
2621 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002622 }
2623}
2624
reeda8db7282015-07-07 10:22:31 -07002625void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002626#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002627 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002628#endif
reede3b38ce2016-01-08 09:18:44 -08002629 RETURN_ON_NULL(dr);
2630 if (matrix && matrix->isIdentity()) {
2631 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002632 }
reede3b38ce2016-01-08 09:18:44 -08002633 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002634}
2635
2636void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002637 // drawable bounds are no longer reliable (e.g. android displaylist)
2638 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002639 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002640}
2641
reed71c3c762015-06-24 10:29:17 -07002642void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002643 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002644 const SkRect* cull, const SkPaint* paint) {
2645 if (cull && this->quickReject(*cull)) {
2646 return;
2647 }
2648
2649 SkPaint pnt;
2650 if (paint) {
2651 pnt = *paint;
2652 }
halcanary9d524f22016-03-29 09:03:52 -07002653
Ben Wagner2c312c42018-06-27 14:46:46 -04002654 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002655 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002656 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002657 }
2658 LOOPER_END
2659}
2660
reedf70b5312016-03-04 16:36:20 -08002661void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2662 SkASSERT(key);
2663
2664 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002665 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002666 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002667 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002668 }
2669 LOOPER_END
2670}
2671
reed@android.com8a1c16f2008-12-17 15:59:43 +00002672//////////////////////////////////////////////////////////////////////////////
2673// These methods are NOT virtual, and therefore must call back into virtual
2674// methods, rather than actually drawing themselves.
2675//////////////////////////////////////////////////////////////////////////////
2676
reed374772b2016-10-05 17:33:02 -07002677void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002678 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002679 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002680 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002681 this->drawPaint(paint);
2682}
2683
2684void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002685 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002686 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2687}
2688
Mike Reed3661bc92017-02-22 13:21:42 -05002689void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002690 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002691 pts[0].set(x0, y0);
2692 pts[1].set(x1, y1);
2693 this->drawPoints(kLines_PointMode, 2, pts, paint);
2694}
2695
Mike Reed3661bc92017-02-22 13:21:42 -05002696void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697 if (radius < 0) {
2698 radius = 0;
2699 }
2700
2701 SkRect r;
2702 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002703 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002704}
2705
2706void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2707 const SkPaint& paint) {
2708 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002709 SkRRect rrect;
2710 rrect.setRectXY(r, rx, ry);
2711 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002712 } else {
2713 this->drawRect(r, paint);
2714 }
2715}
2716
reed@android.com8a1c16f2008-12-17 15:59:43 +00002717void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2718 SkScalar sweepAngle, bool useCenter,
2719 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002720 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002721 if (oval.isEmpty() || !sweepAngle) {
2722 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723 }
bsalomon21af9ca2016-08-25 12:29:23 -07002724 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002725}
2726
reed@android.comf76bacf2009-05-13 14:00:33 +00002727///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002728
Mike Klein88d90712018-01-27 17:30:04 +00002729/**
2730 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2731 * against the playback cost of recursing into the subpicture to get at its actual ops.
2732 *
2733 * For now we pick a conservatively small value, though measurement (and other heuristics like
2734 * the type of ops contained) may justify changing this value.
2735 */
2736#define kMaxPictureOpsToUnrollInsteadOfRef 1
2737
reedd5fa1a42014-08-09 11:08:05 -07002738void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002739 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002740 RETURN_ON_NULL(picture);
2741
reede3b38ce2016-01-08 09:18:44 -08002742 if (matrix && matrix->isIdentity()) {
2743 matrix = nullptr;
2744 }
Mike Klein88d90712018-01-27 17:30:04 +00002745 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2746 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2747 picture->playback(this);
2748 } else {
2749 this->onDrawPicture(picture, matrix, paint);
2750 }
reedd5fa1a42014-08-09 11:08:05 -07002751}
robertphillips9b14f262014-06-04 05:40:44 -07002752
reedd5fa1a42014-08-09 11:08:05 -07002753void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2754 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002755 if (!paint || paint->canComputeFastBounds()) {
2756 SkRect bounds = picture->cullRect();
2757 if (paint) {
2758 paint->computeFastBounds(bounds, &bounds);
2759 }
2760 if (matrix) {
2761 matrix->mapRect(&bounds);
2762 }
2763 if (this->quickReject(bounds)) {
2764 return;
2765 }
2766 }
2767
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002768 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002769 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770}
2771
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772///////////////////////////////////////////////////////////////////////////////
2773///////////////////////////////////////////////////////////////////////////////
2774
reed3aafe112016-08-18 12:45:34 -07002775SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002776 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777
2778 SkASSERT(canvas);
2779
reed3aafe112016-08-18 12:45:34 -07002780 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 fDone = !fImpl->next();
2782}
2783
2784SkCanvas::LayerIter::~LayerIter() {
2785 fImpl->~SkDrawIter();
2786}
2787
2788void SkCanvas::LayerIter::next() {
2789 fDone = !fImpl->next();
2790}
2791
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002792SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002793 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002794}
2795
2796const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002797 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002798}
2799
2800const SkPaint& SkCanvas::LayerIter::paint() const {
2801 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002802 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002803 paint = &fDefaultPaint;
2804 }
2805 return *paint;
2806}
2807
Mike Reedca37f322018-03-08 13:22:16 -05002808SkIRect SkCanvas::LayerIter::clipBounds() const {
2809 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002810}
2811
reed@android.com8a1c16f2008-12-17 15:59:43 +00002812int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2813int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002814
2815///////////////////////////////////////////////////////////////////////////////
2816
Brian Osman10fc6fd2018-03-02 11:01:10 -05002817// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002818static bool supported_for_raster_canvas(const SkImageInfo& info) {
2819 switch (info.alphaType()) {
2820 case kPremul_SkAlphaType:
2821 case kOpaque_SkAlphaType:
2822 break;
2823 default:
2824 return false;
2825 }
2826
2827 switch (info.colorType()) {
2828 case kAlpha_8_SkColorType:
2829 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002830 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002831 case kRGBA_F16_SkColorType:
Mike Klein37854712018-06-26 11:43:06 -04002832 case kRGBA_F32_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002833 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002834 break;
2835 default:
2836 return false;
2837 }
2838
2839 return true;
2840}
2841
Mike Reed5df49342016-11-12 08:06:55 -06002842std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002843 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002844 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002845 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002846 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002847
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002848 SkBitmap bitmap;
2849 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002850 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002851 }
Mike Reed12f77342017-11-08 11:19:52 -05002852
2853 return props ?
2854 skstd::make_unique<SkCanvas>(bitmap, *props) :
2855 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002856}
reedd5fa1a42014-08-09 11:08:05 -07002857
2858///////////////////////////////////////////////////////////////////////////////
2859
Florin Malitaee424ac2016-12-01 12:47:59 -05002860SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2861 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2862
Florin Malita439ace92016-12-02 12:05:41 -05002863SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2864 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2865
Herb Derbyefe39bc2018-05-01 17:06:20 -04002866SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002867 : INHERITED(device) {}
2868
Florin Malitaee424ac2016-12-01 12:47:59 -05002869SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2870 (void)this->INHERITED::getSaveLayerStrategy(rec);
2871 return kNoLayer_SaveLayerStrategy;
2872}
2873
2874///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002875
reed73603f32016-09-20 08:42:38 -07002876static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2877static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2878static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2879static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2880static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2881static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002882
2883///////////////////////////////////////////////////////////////////////////////////////////////////
2884
2885SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2886 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002887 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002888 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2889 SkIPoint origin = dev->getOrigin();
2890 SkMatrix ctm = this->getTotalMatrix();
2891 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2892
2893 SkIRect clip = fMCRec->fRasterClip.getBounds();
2894 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002895 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002896 clip.setEmpty();
2897 }
2898
2899 fAllocator->updateHandle(handle, ctm, clip);
2900 return handle;
2901 }
2902 return nullptr;
2903}
2904
2905static bool install(SkBitmap* bm, const SkImageInfo& info,
2906 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002907 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002908}
2909
2910SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2911 SkBitmap* bm) {
2912 SkRasterHandleAllocator::Rec rec;
2913 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2914 return nullptr;
2915 }
2916 return rec.fHandle;
2917}
2918
2919std::unique_ptr<SkCanvas>
2920SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2921 const SkImageInfo& info, const Rec* rec) {
2922 if (!alloc || !supported_for_raster_canvas(info)) {
2923 return nullptr;
2924 }
2925
2926 SkBitmap bm;
2927 Handle hndl;
2928
2929 if (rec) {
2930 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2931 } else {
2932 hndl = alloc->allocBitmap(info, &bm);
2933 }
2934 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2935}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002936
2937///////////////////////////////////////////////////////////////////////////////////////////////////
2938
2939