blob: f976d71e2069d1e45314cda223ca561c90ba7696 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Hal Canaryc640d0d2018-06-13 09:59:02 -04008#include "SkCanvas.h"
9
Herb Derby73fe7b02017-02-08 15:12:19 -050010#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +000011#include "SkBitmapDevice.h"
reedd5fa1a42014-08-09 11:08:05 -070012#include "SkCanvasPriv.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040013#include "SkClipOpPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070014#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070015#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDraw.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#include "SkDrawLooper.h"
Herb Derby41f4f312018-06-06 17:45:53 +000018#include "SkGlyphCache.h"
19#include "SkGlyphRun.h"
piotaixrb5fae932014-09-24 13:03:30 -070020#include "SkImage.h"
senorblanco900c3672016-04-27 11:31:23 -070021#include "SkImageFilter.h"
22#include "SkImageFilterCache.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040023#include "SkImage_Base.h"
msarettc573a402016-08-02 08:05:56 -070024#include "SkLatticeIter.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040025#include "SkMSAN.h"
Mike Reed5df49342016-11-12 08:06:55 -060026#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080027#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000028#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050029#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070030#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070031#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070032#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040033#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000034#include "SkPicture.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040035#include "SkRRect.h"
reed@google.com00177082011-10-12 14:34:30 +000036#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050037#include "SkRasterHandleAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080038#include "SkSpecialImage.h"
Herb Derby41f4f312018-06-06 17:45:53 +000039#include "SkStrikeCache.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040040#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000041#include "SkSurface_Base.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040042#include "SkTLazy.h"
fmalita7ba7aa72014-08-29 09:46:36 -070043#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000044#include "SkTextFormatParams.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040045#include "SkTo.h"
danakj8f757f52014-11-04 11:48:43 -080046#include "SkTraceEvent.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040047#include "SkVertices.h"
48
bungemand3ebb482015-08-05 13:57:49 -070049#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000050
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080052#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050053#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000054#endif
55
reede3b38ce2016-01-08 09:18:44 -080056#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050057#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080058
Mike Reed139e5e02017-03-08 11:29:33 -050059///////////////////////////////////////////////////////////////////////////////////////////////////
Brian Salomon1da5cad2018-11-21 09:21:18 -050060SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
61 const SkRect& dstRect, unsigned aaFlags)
62 : fImage(std::move(image))
63 , fSrcRect(srcRect)
64 , fDstRect(dstRect)
65 , fAlpha(1.f)
66 , fAAFlags(aaFlags) {}
67
68SkCanvas::ImageSetEntry::ImageSetEntry(sk_sp<const SkImage> image, const SkRect& srcRect,
69 const SkRect& dstRect, float alpha, unsigned aaFlags)
70 : fImage(std::move(image))
71 , fSrcRect(srcRect)
72 , fDstRect(dstRect)
73 , fAlpha(alpha)
74 , fAAFlags(aaFlags) {}
75
76///////////////////////////////////////////////////////////////////////////////////////////////////
Mike Reed139e5e02017-03-08 11:29:33 -050077
reedc83a2972015-07-16 07:40:45 -070078/*
79 * Return true if the drawing this rect would hit every pixels in the canvas.
80 *
81 * Returns false if
82 * - rect does not contain the canvas' bounds
83 * - paint is not fill
84 * - paint would blur or otherwise change the coverage of the rect
85 */
86bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
87 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070088 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
89 (int)kNone_ShaderOverrideOpacity,
90 "need_matching_enums0");
91 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
92 (int)kOpaque_ShaderOverrideOpacity,
93 "need_matching_enums1");
94 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
95 (int)kNotOpaque_ShaderOverrideOpacity,
96 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070097
98 const SkISize size = this->getBaseLayerSize();
99 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -0500100
101 // if we're clipped at all, we can't overwrite the entire surface
102 {
103 SkBaseDevice* base = this->getDevice();
104 SkBaseDevice* top = this->getTopDevice();
105 if (base != top) {
106 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
107 }
108 if (!base->clipIsWideOpen()) {
109 return false;
110 }
reedc83a2972015-07-16 07:40:45 -0700111 }
112
113 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -0700114 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -0700115 return false; // conservative
116 }
halcanaryc5769b22016-08-10 07:13:21 -0700117
118 SkRect devRect;
119 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
120 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700121 return false;
122 }
123 }
124
125 if (paint) {
126 SkPaint::Style paintStyle = paint->getStyle();
127 if (!(paintStyle == SkPaint::kFill_Style ||
128 paintStyle == SkPaint::kStrokeAndFill_Style)) {
129 return false;
130 }
131 if (paint->getMaskFilter() || paint->getLooper()
132 || paint->getPathEffect() || paint->getImageFilter()) {
133 return false; // conservative
134 }
135 }
136 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
137}
138
139///////////////////////////////////////////////////////////////////////////////////////////////////
140
reed@google.comda17f752012-08-16 18:27:05 +0000141// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142//#define SK_TRACE_SAVERESTORE
143
144#ifdef SK_TRACE_SAVERESTORE
145 static int gLayerCounter;
146 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
147 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
148
149 static int gRecCounter;
150 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
151 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
152
153 static int gCanvasCounter;
154 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
155 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
156#else
157 #define inc_layer()
158 #define dec_layer()
159 #define inc_rec()
160 #define dec_rec()
161 #define inc_canvas()
162 #define dec_canvas()
163#endif
164
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000165typedef SkTLazy<SkPaint> SkLazyPaint;
166
reedc83a2972015-07-16 07:40:45 -0700167void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000168 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700169 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
170 ? SkSurface::kDiscard_ContentChangeMode
171 : SkSurface::kRetain_ContentChangeMode);
172 }
173}
174
175void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
176 ShaderOverrideOpacity overrideOpacity) {
177 if (fSurfaceBase) {
178 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
179 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
180 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
181 // and therefore we don't care which mode we're in.
182 //
183 if (fSurfaceBase->outstandingImageSnapshot()) {
184 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
185 mode = SkSurface::kDiscard_ContentChangeMode;
186 }
187 }
188 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000189 }
190}
191
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000194/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195 The clip/matrix/proc are fields that reflect the top of the save/restore
196 stack. Whenever the canvas changes, it marks a dirty flag, and then before
197 these are used (assuming we're not on a layer) we rebuild these cache
198 values: they reflect the top of the save stack, but translated and clipped
199 by the device's XY offset and bitmap-bounds.
200*/
201struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400202 DeviceCM* fNext;
203 sk_sp<SkBaseDevice> fDevice;
204 SkRasterClip fClip;
205 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
206 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400207 sk_sp<SkImage> fClipImage;
208 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209
Florin Malita53f77bd2017-04-28 13:48:37 -0400210 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000211 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700212 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400213 , fDevice(std::move(device))
214 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700215 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000216 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400217 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400218 {}
reed@google.com4b226022011-01-11 18:32:13 +0000219
mtkleinfeaadee2015-04-08 11:25:48 -0700220 void reset(const SkIRect& bounds) {
221 SkASSERT(!fPaint);
222 SkASSERT(!fNext);
223 SkASSERT(fDevice);
224 fClip.setRect(bounds);
225 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226};
227
228/* This is the record we keep for each save/restore level in the stack.
229 Since a level optionally copies the matrix and/or stack, we have pointers
230 for these fields. If the value is copied for this level, the copy is
231 stored in the ...Storage field, and the pointer points to that. If the
232 value is not copied for this level, we ignore ...Storage, and just point
233 at the corresponding value in the previous level in the stack.
234*/
235class SkCanvas::MCRec {
236public:
reedd9544982014-09-09 18:46:22 -0700237 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 /* If there are any layers in the stack, this points to the top-most
239 one that is at or below this level in the stack (so we know what
240 bitmap/device to draw into from this level. This value is NOT
241 reference counted, since the real owner is either our fLayer field,
242 or a previous one in a lower level.)
243 */
Mike Reeda1361362017-03-07 09:37:29 -0500244 DeviceCM* fTopLayer;
245 SkConservativeClip fRasterClip;
246 SkMatrix fMatrix;
247 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248
Mike Reeda1361362017-03-07 09:37:29 -0500249 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700250 fLayer = nullptr;
251 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800252 fMatrix.reset();
253 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700254
reedd9544982014-09-09 18:46:22 -0700255 // don't bother initializing fNext
256 inc_rec();
257 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400258 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700259 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700260 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800261 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700262
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 // don't bother initializing fNext
264 inc_rec();
265 }
266 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700267 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 dec_rec();
269 }
mtkleinfeaadee2015-04-08 11:25:48 -0700270
271 void reset(const SkIRect& bounds) {
272 SkASSERT(fLayer);
273 SkASSERT(fDeferredSaveCount == 0);
274
275 fMatrix.reset();
276 fRasterClip.setRect(bounds);
277 fLayer->reset(bounds);
278 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279};
280
Mike Reeda1361362017-03-07 09:37:29 -0500281class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282public:
Mike Reeda1361362017-03-07 09:37:29 -0500283 SkDrawIter(SkCanvas* canvas)
284 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
285 {}
reed@google.com4b226022011-01-11 18:32:13 +0000286
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000288 const DeviceCM* rec = fCurrLayer;
289 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400290 fDevice = rec->fDevice.get();
291 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700293 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 return true;
295 }
296 return false;
297 }
reed@google.com4b226022011-01-11 18:32:13 +0000298
reed@google.com6f8f2922011-03-04 22:27:10 +0000299 int getX() const { return fDevice->getOrigin().x(); }
300 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000302
Mike Reed99330ba2017-02-22 11:01:08 -0500303 SkBaseDevice* fDevice;
304
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306 const DeviceCM* fCurrLayer;
307 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000308};
309
Florin Malita713b8ef2017-04-28 10:57:24 -0400310#define FOR_EACH_TOP_DEVICE( code ) \
311 do { \
312 DeviceCM* layer = fMCRec->fTopLayer; \
313 while (layer) { \
314 SkBaseDevice* device = layer->fDevice.get(); \
315 if (device) { \
316 code; \
317 } \
318 layer = layer->fNext; \
319 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500320 } while (0)
321
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322/////////////////////////////////////////////////////////////////////////////
323
reeddbc3cef2015-04-29 12:18:57 -0700324static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
325 return lazy->isValid() ? lazy->get() : lazy->set(orig);
326}
327
328/**
329 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700330 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700331 */
reedd053ce92016-03-22 10:17:23 -0700332static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700333 SkImageFilter* imgf = paint.getImageFilter();
334 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700335 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700336 }
337
reedd053ce92016-03-22 10:17:23 -0700338 SkColorFilter* imgCFPtr;
339 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700340 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700341 }
reedd053ce92016-03-22 10:17:23 -0700342 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700343
344 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700345 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700346 // there is no existing paint colorfilter, so we can just return the imagefilter's
347 return imgCF;
348 }
349
350 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
351 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500352 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700353}
354
senorblanco87e066e2015-10-28 11:23:36 -0700355/**
356 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
357 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
358 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
359 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
360 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
361 * conservative "effective" bounds based on the settings in the paint... with one exception. This
362 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
363 * deliberately ignored.
364 */
365static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
366 const SkRect& rawBounds,
367 SkRect* storage) {
368 SkPaint tmpUnfiltered(paint);
369 tmpUnfiltered.setImageFilter(nullptr);
370 if (tmpUnfiltered.canComputeFastBounds()) {
371 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
372 } else {
373 return rawBounds;
374 }
375}
376
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377class AutoDrawLooper {
378public:
senorblanco87e066e2015-10-28 11:23:36 -0700379 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
380 // paint. It's used to determine the size of the offscreen layer for filters.
381 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700382 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700383 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000384 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700385 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000386 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700387 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000388 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000389
reedd053ce92016-03-22 10:17:23 -0700390 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700391 if (simplifiedCF) {
392 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700393 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700394 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700395 fPaint = paint;
396 }
397
398 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700399 /**
400 * We implement ImageFilters for a given draw by creating a layer, then applying the
401 * imagefilter to the pixels of that layer (its backing surface/image), and then
402 * we call restore() to xfer that layer to the main canvas.
403 *
404 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
405 * 2. Generate the src pixels:
406 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
407 * return (fPaint). We then draw the primitive (using srcover) into a cleared
408 * buffer/surface.
409 * 3. Restore the layer created in #1
410 * The imagefilter is passed the buffer/surface from the layer (now filled with the
411 * src pixels of the primitive). It returns a new "filtered" buffer, which we
412 * draw onto the previous layer using the xfermode from the original paint.
413 */
reed@google.com8926b162012-03-23 15:36:36 +0000414 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500415 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700416 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700417 SkRect storage;
418 if (rawBounds) {
419 // Make rawBounds include all paint outsets except for those due to image filters.
420 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
421 }
reedbfd5f172016-01-07 11:28:08 -0800422 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700423 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700424 fTempLayerForImageFilter = true;
425 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000426 }
427
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000428 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500429 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000430 fIsSimple = false;
431 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700432 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000433 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400434 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000435 }
436 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000437
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700439 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000440 fCanvas->internalRestore();
441 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000442 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000444
reed@google.com4e2b3d32011-04-07 14:18:59 +0000445 const SkPaint& paint() const {
446 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400447 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000448 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000450
Ben Wagner2c312c42018-06-27 14:46:46 -0400451 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000452 if (fDone) {
453 return false;
454 } else if (fIsSimple) {
455 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000456 return !fPaint->nothingToDraw();
457 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400458 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000459 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000460 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000461
reed@android.com8a1c16f2008-12-17 15:59:43 +0000462private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500463 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700464 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000465 SkCanvas* fCanvas;
466 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000467 const SkPaint* fPaint;
468 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700469 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000470 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000471 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000472 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400473 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000474
Ben Wagner2c312c42018-06-27 14:46:46 -0400475 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000476};
477
Ben Wagner2c312c42018-06-27 14:46:46 -0400478bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700479 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000480 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400481 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000482
reeddbc3cef2015-04-29 12:18:57 -0700483 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
484 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400485 // never want our downstream clients (i.e. devices) to see loopers
486 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000487
reed5c476fb2015-04-20 08:04:21 -0700488 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700489 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700490 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000491 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000492
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000493 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000494 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000495 return false;
496 }
reed@google.com129ec222012-05-15 13:24:09 +0000497 fPaint = paint;
498
499 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400500 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000501 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000502 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000503 return true;
504}
505
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506////////// macros to place around the internal draw calls //////////////////
507
reed3aafe112016-08-18 12:45:34 -0700508#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
509 this->predrawNotify(); \
510 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400511 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800512 SkDrawIter iter(this);
513
514
Ben Wagner2c312c42018-06-27 14:46:46 -0400515#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000516 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700517 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400518 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000519 SkDrawIter iter(this);
520
Ben Wagner2c312c42018-06-27 14:46:46 -0400521#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000522 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700523 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400524 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000526
Ben Wagner2c312c42018-06-27 14:46:46 -0400527#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700528 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700529 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400530 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700531 SkDrawIter iter(this);
532
reed@google.com4e2b3d32011-04-07 14:18:59 +0000533#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534
535////////////////////////////////////////////////////////////////////////////
536
msarettfbfa2582016-08-12 08:29:08 -0700537static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
538 if (bounds.isEmpty()) {
539 return SkRect::MakeEmpty();
540 }
541
542 // Expand bounds out by 1 in case we are anti-aliasing. We store the
543 // bounds as floats to enable a faster quick reject implementation.
544 SkRect dst;
545 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
546 return dst;
547}
548
mtkleinfeaadee2015-04-08 11:25:48 -0700549void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
550 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700551 fMCRec->reset(bounds);
552
553 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500554 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400555 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700556 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700557 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700558}
559
Hal Canary363a3f82018-10-04 11:04:48 -0400560void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000561 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800562 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700563 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000564
565 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500566 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500567 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700568 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000569
reeda499f902015-05-01 09:34:31 -0700570 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
571 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400572 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700573
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575
halcanary96fcdcc2015-08-27 07:41:13 -0700576 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000577
reedf92c8662014-08-18 08:02:43 -0700578 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700579 // The root device and the canvas should always have the same pixel geometry
580 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800581 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700582 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500583
Mike Reedc42a1cd2017-02-14 14:25:14 -0500584 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700585 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400586
Herb Derby59d997a2018-06-07 12:44:09 -0400587 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588}
589
reed@google.comcde92112011-07-06 20:00:52 +0000590SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000591 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700592 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000593{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000594 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000595
Hal Canary363a3f82018-10-04 11:04:48 -0400596 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000597}
598
reed96a857e2015-01-25 10:33:58 -0800599SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000600 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800601 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000602{
603 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400604 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400605 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700606}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000607
Hal Canary363a3f82018-10-04 11:04:48 -0400608SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700609 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700610 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700611{
612 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700613
Mike Reed566e53c2017-03-10 10:49:45 -0500614 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400615 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700616}
617
Herb Derbyefe39bc2018-05-01 17:06:20 -0400618SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000619 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700620 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000621{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000622 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700623
Hal Canary363a3f82018-10-04 11:04:48 -0400624 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700625}
626
reed4a8126e2014-09-22 07:29:03 -0700627SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700628 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700629 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700630{
631 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700632
Mike Reed910ca0f2018-04-25 13:04:05 -0400633 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400634 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700635}
reed29c857d2014-09-21 10:25:07 -0700636
Mike Reed356f7c22017-01-10 11:58:39 -0500637SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
638 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700639 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
640 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500641 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700642{
643 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700644
Mike Reed910ca0f2018-04-25 13:04:05 -0400645 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400646 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647}
648
Mike Reed356f7c22017-01-10 11:58:39 -0500649SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
650
Matt Sarett31f99ce2017-04-11 08:46:01 -0400651#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
652SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
653 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
654 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
655 , fAllocator(nullptr)
656{
657 inc_canvas();
658
659 SkBitmap tmp(bitmap);
660 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400661 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400662 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400663}
664#endif
665
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666SkCanvas::~SkCanvas() {
667 // free up the contents of our deque
668 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000669
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670 this->internalRestore(); // restore the last, since we're going away
671
halcanary385fe4d2015-08-26 13:07:48 -0700672 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000673
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674 dec_canvas();
675}
676
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000677SkMetaData& SkCanvas::getMetaData() {
678 // metadata users are rare, so we lazily allocate it. If that changes we
679 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700680 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000681 fMetaData = new SkMetaData;
682 }
683 return *fMetaData;
684}
685
reed@android.com8a1c16f2008-12-17 15:59:43 +0000686///////////////////////////////////////////////////////////////////////////////
687
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000688void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700689 this->onFlush();
690}
691
692void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000693 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000694 if (device) {
695 device->flush();
696 }
697}
698
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000699SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000700 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000701 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
702}
703
senorblancoafc7cce2016-02-02 18:44:15 -0800704SkIRect SkCanvas::getTopLayerBounds() const {
705 SkBaseDevice* d = this->getTopDevice();
706 if (!d) {
707 return SkIRect::MakeEmpty();
708 }
709 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
710}
711
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000712SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000713 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000714 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000715 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400716 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000717}
718
Florin Malita0ed3b642017-01-13 16:56:38 +0000719SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400720 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000721}
722
Mike Reed353196f2017-07-21 11:01:18 -0400723bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000724 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400725 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000726}
727
Mike Reed353196f2017-07-21 11:01:18 -0400728bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
729 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400730}
731
732bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
733 SkPixmap pm;
734 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
735}
736
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000737bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400738 SkPixmap pm;
739 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700740 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000741 }
742 return false;
743}
744
Matt Sarett03dd6d52017-01-23 12:15:09 -0500745bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000746 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000747 SkBaseDevice* device = this->getDevice();
748 if (!device) {
749 return false;
750 }
751
Matt Sarett03dd6d52017-01-23 12:15:09 -0500752 // This check gives us an early out and prevents generation ID churn on the surface.
753 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
754 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
755 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
756 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000757 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000758
Matt Sarett03dd6d52017-01-23 12:15:09 -0500759 // Tell our owning surface to bump its generation ID.
760 const bool completeOverwrite =
761 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700762 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700763
Matt Sarett03dd6d52017-01-23 12:15:09 -0500764 // This can still fail, most notably in the case of a invalid color type or alpha type
765 // conversion. We could pull those checks into this function and avoid the unnecessary
766 // generation ID bump. But then we would be performing those checks twice, since they
767 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400768 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000769}
reed@google.com51df9e32010-12-23 19:29:18 +0000770
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771//////////////////////////////////////////////////////////////////////////////
772
reed2ff1fce2014-12-11 07:07:37 -0800773void SkCanvas::checkForDeferredSave() {
774 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800775 this->doSave();
776 }
777}
778
reedf0090cb2014-11-26 08:55:51 -0800779int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800780#ifdef SK_DEBUG
781 int count = 0;
782 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
783 for (;;) {
784 const MCRec* rec = (const MCRec*)iter.next();
785 if (!rec) {
786 break;
787 }
788 count += 1 + rec->fDeferredSaveCount;
789 }
790 SkASSERT(count == fSaveCount);
791#endif
792 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800793}
794
795int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800796 fSaveCount += 1;
797 fMCRec->fDeferredSaveCount += 1;
798 return this->getSaveCount() - 1; // return our prev value
799}
800
801void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800802 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700803
804 SkASSERT(fMCRec->fDeferredSaveCount > 0);
805 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800806 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800807}
808
809void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800810 if (fMCRec->fDeferredSaveCount > 0) {
811 SkASSERT(fSaveCount > 1);
812 fSaveCount -= 1;
813 fMCRec->fDeferredSaveCount -= 1;
814 } else {
815 // check for underflow
816 if (fMCStack.count() > 1) {
817 this->willRestore();
818 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700819 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800820 this->internalRestore();
821 this->didRestore();
822 }
reedf0090cb2014-11-26 08:55:51 -0800823 }
824}
825
826void SkCanvas::restoreToCount(int count) {
827 // sanity check
828 if (count < 1) {
829 count = 1;
830 }
mtkleinf0f14112014-12-12 08:46:25 -0800831
reedf0090cb2014-11-26 08:55:51 -0800832 int n = this->getSaveCount() - count;
833 for (int i = 0; i < n; ++i) {
834 this->restore();
835 }
836}
837
reed2ff1fce2014-12-11 07:07:37 -0800838void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000839 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700840 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000841 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000842
Mike Reedc42a1cd2017-02-14 14:25:14 -0500843 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000844}
845
reed4960eee2015-12-18 07:09:18 -0800846bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400847 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000848}
849
reed4960eee2015-12-18 07:09:18 -0800850bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700851 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500852 SkIRect clipBounds = this->getDeviceClipBounds();
853 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000854 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000855 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000856
reed96e657d2015-03-10 17:30:07 -0700857 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
858
Robert Phillips12078432018-05-17 11:17:39 -0400859 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
860 // If the image filter DAG affects transparent black then we will need to render
861 // out to the clip bounds
862 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000863 }
Robert Phillips12078432018-05-17 11:17:39 -0400864
865 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700866 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700868 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400869 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000870 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400871 inputSaveLayerBounds = clipBounds;
872 }
873
874 if (imageFilter) {
875 // expand the clip bounds by the image filter DAG to include extra content that might
876 // be required by the image filters.
877 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
878 SkImageFilter::kReverse_MapDirection,
879 &inputSaveLayerBounds);
880 }
881
882 SkIRect clippedSaveLayerBounds;
883 if (bounds) {
884 // For better or for worse, user bounds currently act as a hard clip on the layer's
885 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
886 clippedSaveLayerBounds = inputSaveLayerBounds;
887 } else {
888 // If there are no user bounds, we don't want to artificially restrict the resulting
889 // layer bounds, so allow the expanded clip bounds free reign.
890 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000891 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800892
893 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400894 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800895 if (BoundsAffectsClip(saveLayerFlags)) {
896 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
897 fMCRec->fRasterClip.setEmpty();
898 fDeviceClipBounds.setEmpty();
899 }
900 return false;
901 }
Robert Phillips12078432018-05-17 11:17:39 -0400902 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000903
reed4960eee2015-12-18 07:09:18 -0800904 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700905 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400906 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
907 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000908 }
909
910 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400911 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000912 }
Robert Phillips12078432018-05-17 11:17:39 -0400913
junov@chromium.orga907ac32012-02-24 21:54:07 +0000914 return true;
915}
916
reed4960eee2015-12-18 07:09:18 -0800917int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
918 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000919}
920
reed70ee31b2015-12-10 13:44:45 -0800921int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800922 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
923}
924
Cary Clarke041e312018-03-06 13:00:52 -0500925int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700926 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400927 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
928 // no need for the layer (or any of the draws until the matching restore()
929 this->save();
930 this->clipRect({0,0,0,0});
931 } else {
932 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
933 fSaveCount += 1;
934 this->internalSaveLayer(rec, strategy);
935 }
reed4960eee2015-12-18 07:09:18 -0800936 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800937}
938
reeda2217ef2016-07-20 06:04:34 -0700939void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500940 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500941 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700942 SkDraw draw;
943 SkRasterClip rc;
944 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
945 if (!dst->accessPixels(&draw.fDst)) {
946 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800947 }
reeda2217ef2016-07-20 06:04:34 -0700948 draw.fMatrix = &SkMatrix::I();
949 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800950
951 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500952 if (filter) {
953 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
954 }
reeda2217ef2016-07-20 06:04:34 -0700955
Mike Reedc42a1cd2017-02-14 14:25:14 -0500956 int x = src->getOrigin().x() - dstOrigin.x();
957 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700958 auto special = src->snapSpecial();
959 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400960 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700961 }
robertphillips7354a4b2015-12-16 05:08:27 -0800962}
reed70ee31b2015-12-10 13:44:45 -0800963
Mike Kleine083f7c2018-02-07 12:54:27 -0500964static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500965 // Need to force L32 for now if we have an image filter.
966 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
967 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500968 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800969 }
Mike Klein649fb732018-02-26 15:09:16 -0500970
971 SkColorType ct = prev.colorType();
972 if (prev.bytesPerPixel() <= 4) {
973 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
974 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
975 ct = kN32_SkColorType;
976 }
977 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800978}
979
reed4960eee2015-12-18 07:09:18 -0800980void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700981 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800982 const SkRect* bounds = rec.fBounds;
983 const SkPaint* paint = rec.fPaint;
984 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
985
reed8c30a812016-04-20 16:36:51 -0700986 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400987 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700988 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400989 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700990 SkMatrix remainder;
991 SkSize scale;
992 /*
993 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
994 * but they do handle scaling. To accommodate this, we do the following:
995 *
996 * 1. Stash off the current CTM
997 * 2. Decompose the CTM into SCALE and REMAINDER
998 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
999 * contains the REMAINDER
1000 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1001 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1002 * of the original imagefilter, and draw that (via drawSprite)
1003 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1004 *
1005 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1006 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1007 */
reed96a04f32016-04-25 09:25:15 -07001008 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001009 stashedMatrix.decomposeScale(&scale, &remainder))
1010 {
1011 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001012 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001013 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1014 SkPaint* p = lazyP.set(*paint);
1015 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1016 SkFilterQuality::kLow_SkFilterQuality,
1017 sk_ref_sp(imageFilter)));
1018 imageFilter = p->getImageFilter();
1019 paint = p;
1020 }
reed8c30a812016-04-20 16:36:51 -07001021
junov@chromium.orga907ac32012-02-24 21:54:07 +00001022 // do this before we create the layer. We don't call the public save() since
1023 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001024 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001025
junov@chromium.orga907ac32012-02-24 21:54:07 +00001026 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001027 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001028 if (modifiedRec) {
1029 // In this case there will be no layer in which to stash the matrix so we need to
1030 // revert the prior MCRec to its earlier state.
1031 modifiedRec->fMatrix = stashedMatrix;
1032 }
reed2ff1fce2014-12-11 07:07:37 -08001033 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001034 }
1035
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001036 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1037 // the clipRectBounds() call above?
1038 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001039 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001040 }
1041
reed8dc0ccb2015-03-20 06:32:52 -07001042 SkPixelGeometry geo = fProps.pixelGeometry();
1043 if (paint) {
reed76033be2015-03-14 10:54:31 -07001044 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001045 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001046 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001047 }
1048 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001049
robertphillips5139e502016-07-19 05:10:40 -07001050 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001051 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001052 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001053 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001054 }
reedb2db8982014-11-13 12:41:02 -08001055
Mike Kleine083f7c2018-02-07 12:54:27 -05001056 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001057
Hal Canary704cd322016-11-07 14:13:52 -05001058 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001059 {
reed70ee31b2015-12-10 13:44:45 -08001060 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001061 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001062 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001063 const bool trackCoverage =
1064 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001065 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001066 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001067 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001068 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001069 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1070 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001071 return;
reed61f501f2015-04-29 08:34:00 -07001072 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001073 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001074 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001075
Mike Reedb43a3e02017-02-11 10:18:58 -05001076 // only have a "next" if this new layer doesn't affect the clip (rare)
1077 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001078 fMCRec->fLayer = layer;
1079 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001080
Mike Reedc61abee2017-02-28 17:45:27 -05001081 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001082 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001083 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001084 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001085
Mike Reedc42a1cd2017-02-14 14:25:14 -05001086 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1087
1088 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1089 if (layer->fNext) {
1090 // need to punch a hole in the previous device, so we don't draw there, given that
1091 // the new top-layer will allow drawing to happen "below" it.
1092 SkRegion hole(ir);
1093 do {
1094 layer = layer->fNext;
1095 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1096 } while (layer->fNext);
1097 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098}
1099
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001100int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001101 if (0xFF == alpha) {
1102 return this->saveLayer(bounds, nullptr);
1103 } else {
1104 SkPaint tmpPaint;
1105 tmpPaint.setAlpha(alpha);
1106 return this->saveLayer(bounds, &tmpPaint);
1107 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001108}
1109
reed@android.com8a1c16f2008-12-17 15:59:43 +00001110void SkCanvas::internalRestore() {
1111 SkASSERT(fMCStack.count() != 0);
1112
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001113 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001114 DeviceCM* layer = fMCRec->fLayer; // may be null
1115 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001116 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001117
1118 // now do the normal restore()
1119 fMCRec->~MCRec(); // balanced in save()
1120 fMCStack.pop_back();
1121 fMCRec = (MCRec*)fMCStack.back();
1122
Mike Reedc42a1cd2017-02-14 14:25:14 -05001123 if (fMCRec) {
1124 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1125 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001126
reed@android.com8a1c16f2008-12-17 15:59:43 +00001127 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1128 since if we're being recorded, we don't want to record this (the
1129 recorder will have already recorded the restore).
1130 */
bsalomon49f085d2014-09-05 13:34:00 -07001131 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001132 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001133 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001134 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001135 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001136 layer->fPaint.get(),
1137 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001138 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001139 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001140 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001141 delete layer;
reedb679ca82015-04-07 04:40:48 -07001142 } else {
1143 // we're at the root
reeda499f902015-05-01 09:34:31 -07001144 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001145 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001146 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001148 }
msarettfbfa2582016-08-12 08:29:08 -07001149
1150 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001151 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001152 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1153 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001154}
1155
reede8f30622016-03-23 18:59:25 -07001156sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001157 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001158 props = &fProps;
1159 }
1160 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001161}
1162
reede8f30622016-03-23 18:59:25 -07001163sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001164 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001165 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001166}
1167
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001168SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001169 return this->onImageInfo();
1170}
1171
1172SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001173 SkBaseDevice* dev = this->getDevice();
1174 if (dev) {
1175 return dev->imageInfo();
1176 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001177 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001178 }
1179}
1180
brianosman898235c2016-04-06 07:38:23 -07001181bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001182 return this->onGetProps(props);
1183}
1184
1185bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001186 SkBaseDevice* dev = this->getDevice();
1187 if (dev) {
1188 if (props) {
1189 *props = fProps;
1190 }
1191 return true;
1192 } else {
1193 return false;
1194 }
1195}
1196
reed6ceeebd2016-03-09 14:26:26 -08001197bool SkCanvas::peekPixels(SkPixmap* pmap) {
1198 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001199}
1200
reed884e97c2015-05-26 11:31:54 -07001201bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001202 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001203 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001204}
1205
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001206void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001207 SkPixmap pmap;
1208 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001209 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001210 }
1211 if (info) {
1212 *info = pmap.info();
1213 }
1214 if (rowBytes) {
1215 *rowBytes = pmap.rowBytes();
1216 }
1217 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001218 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001219 }
reed884e97c2015-05-26 11:31:54 -07001220 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001221}
1222
reed884e97c2015-05-26 11:31:54 -07001223bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001224 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001225 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001226}
1227
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001229
Florin Malita53f77bd2017-04-28 13:48:37 -04001230void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1231 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001232 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001233 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001234 paint = &tmp;
1235 }
reed@google.com4b226022011-01-11 18:32:13 +00001236
Ben Wagner2c312c42018-06-27 14:46:46 -04001237 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001238
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001240 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001241 paint = &looper.paint();
1242 SkImageFilter* filter = paint->getImageFilter();
1243 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001244 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001245 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1246 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001247 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1248 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001249 }
reed@google.com76dd2772012-01-05 21:15:07 +00001250 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001251 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001252 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001253 }
reeda2217ef2016-07-20 06:04:34 -07001254
reed@google.com4e2b3d32011-04-07 14:18:59 +00001255 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001256}
1257
reed32704672015-12-16 08:27:10 -08001258/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001259
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001260void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001261 if (dx || dy) {
1262 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001263 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001264
reedfe69b502016-09-12 06:31:48 -07001265 // Translate shouldn't affect the is-scale-translateness of the matrix.
1266 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001267
Mike Reedc42a1cd2017-02-14 14:25:14 -05001268 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001269
reedfe69b502016-09-12 06:31:48 -07001270 this->didTranslate(dx,dy);
1271 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272}
1273
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001274void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001275 SkMatrix m;
1276 m.setScale(sx, sy);
1277 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278}
1279
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001280void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001281 SkMatrix m;
1282 m.setRotate(degrees);
1283 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001284}
1285
bungeman7438bfc2016-07-12 15:01:19 -07001286void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1287 SkMatrix m;
1288 m.setRotate(degrees, px, py);
1289 this->concat(m);
1290}
1291
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001292void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001293 SkMatrix m;
1294 m.setSkew(sx, sy);
1295 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001296}
1297
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001298void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001299 if (matrix.isIdentity()) {
1300 return;
1301 }
1302
reed2ff1fce2014-12-11 07:07:37 -08001303 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001304 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001305 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001306
Mike Reed7627fa52017-02-08 10:07:53 -05001307 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001308
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001309 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001310}
1311
reed8c30a812016-04-20 16:36:51 -07001312void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001313 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001314 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001315
Mike Reedc42a1cd2017-02-14 14:25:14 -05001316 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001317}
1318
1319void SkCanvas::setMatrix(const SkMatrix& matrix) {
1320 this->checkForDeferredSave();
1321 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001322 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323}
1324
reed@android.com8a1c16f2008-12-17 15:59:43 +00001325void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001326 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001327}
1328
1329//////////////////////////////////////////////////////////////////////////////
1330
Mike Reedc1f77742016-12-09 09:00:50 -05001331void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001332 if (!rect.isFinite()) {
1333 return;
1334 }
reed2ff1fce2014-12-11 07:07:37 -08001335 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001336 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1337 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001338}
1339
Mike Reedc1f77742016-12-09 09:00:50 -05001340void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001341 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001342
Mike Reed7627fa52017-02-08 10:07:53 -05001343 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001344
reedc64eff52015-11-21 12:39:45 -08001345 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001346 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1347 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001348 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001349}
1350
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001351void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1352 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001353 if (fClipRestrictionRect.isEmpty()) {
1354 // we notify the device, but we *dont* resolve deferred saves (since we're just
1355 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001356 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001357 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001358 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001359 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001360 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001361 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001362 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1363 }
1364}
1365
Mike Reedc1f77742016-12-09 09:00:50 -05001366void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001367 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001368 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001369 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001370 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1371 } else {
1372 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001373 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001374}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001375
Mike Reedc1f77742016-12-09 09:00:50 -05001376void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001377 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001378
Brian Salomona3b45d42016-10-03 11:36:16 -04001379 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001380
Mike Reed7627fa52017-02-08 10:07:53 -05001381 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001382
Mike Reed20800c82017-11-15 16:09:04 -05001383 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1384 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001385 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001386}
1387
Mike Reedc1f77742016-12-09 09:00:50 -05001388void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001389 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001390 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001391
1392 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1393 SkRect r;
1394 if (path.isRect(&r)) {
1395 this->onClipRect(r, op, edgeStyle);
1396 return;
1397 }
1398 SkRRect rrect;
1399 if (path.isOval(&r)) {
1400 rrect.setOval(r);
1401 this->onClipRRect(rrect, op, edgeStyle);
1402 return;
1403 }
1404 if (path.isRRect(&rrect)) {
1405 this->onClipRRect(rrect, op, edgeStyle);
1406 return;
1407 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001408 }
robertphillips39f05382015-11-24 09:30:12 -08001409
1410 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001411}
1412
Mike Reedc1f77742016-12-09 09:00:50 -05001413void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001414 AutoValidateClip avc(this);
1415
Brian Salomona3b45d42016-10-03 11:36:16 -04001416 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001417
Mike Reed7627fa52017-02-08 10:07:53 -05001418 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001419
Brian Salomona3b45d42016-10-03 11:36:16 -04001420 const SkPath* rasterClipPath = &path;
1421 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001422 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1423 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001424 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001425}
1426
Mike Reedc1f77742016-12-09 09:00:50 -05001427void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001428 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001429 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001430}
1431
Mike Reedc1f77742016-12-09 09:00:50 -05001432void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001433 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001434
reed@google.com5c3d1472011-02-22 19:12:23 +00001435 AutoValidateClip avc(this);
1436
Mike Reed20800c82017-11-15 16:09:04 -05001437 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001438 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001439}
1440
reed@google.com819c9212011-02-23 18:56:55 +00001441#ifdef SK_DEBUG
1442void SkCanvas::validateClip() const {
1443 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001444 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001445 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001446 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001447 return;
1448 }
reed@google.com819c9212011-02-23 18:56:55 +00001449}
1450#endif
1451
Mike Reeda1361362017-03-07 09:37:29 -05001452bool SkCanvas::androidFramework_isClipAA() const {
1453 bool containsAA = false;
1454
1455 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1456
1457 return containsAA;
1458}
1459
1460class RgnAccumulator {
1461 SkRegion* fRgn;
1462public:
1463 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1464 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1465 SkIPoint origin = device->getOrigin();
1466 if (origin.x() | origin.y()) {
1467 rgn->translate(origin.x(), origin.y());
1468 }
1469 fRgn->op(*rgn, SkRegion::kUnion_Op);
1470 }
1471};
1472
1473void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1474 RgnAccumulator accum(rgn);
1475 SkRegion tmp;
1476
1477 rgn->setEmpty();
1478 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001479}
1480
reed@google.com5c3d1472011-02-22 19:12:23 +00001481///////////////////////////////////////////////////////////////////////////////
1482
reed@google.com754de5f2014-02-24 19:38:20 +00001483bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001484 return fMCRec->fRasterClip.isEmpty();
1485
1486 // TODO: should we only use the conservative answer in a recording canvas?
1487#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001488 SkBaseDevice* dev = this->getTopDevice();
1489 // if no device we return true
1490 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001491#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001492}
1493
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001494bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001495 SkBaseDevice* dev = this->getTopDevice();
1496 // if no device we return false
1497 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001498}
1499
msarettfbfa2582016-08-12 08:29:08 -07001500static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1501#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1502 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1503 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1504 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1505 return 0xF != _mm_movemask_ps(mask);
1506#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1507 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1508 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1509 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1510 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1511#else
1512 SkRect devRectAsRect;
1513 SkRect devClipAsRect;
1514 devRect.store(&devRectAsRect.fLeft);
1515 devClip.store(&devClipAsRect.fLeft);
1516 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1517#endif
1518}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001519
msarettfbfa2582016-08-12 08:29:08 -07001520// It's important for this function to not be inlined. Otherwise the compiler will share code
1521// between the fast path and the slow path, resulting in two slow paths.
1522static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1523 const SkMatrix& matrix) {
1524 SkRect deviceRect;
1525 matrix.mapRect(&deviceRect, src);
1526 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1527}
1528
1529bool SkCanvas::quickReject(const SkRect& src) const {
1530#ifdef SK_DEBUG
1531 // Verify that fDeviceClipBounds are set properly.
1532 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001533 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001534 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001535 } else {
msarettfbfa2582016-08-12 08:29:08 -07001536 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001537 }
msarettfbfa2582016-08-12 08:29:08 -07001538
msarett9637ea92016-08-18 14:03:30 -07001539 // Verify that fIsScaleTranslate is set properly.
1540 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001541#endif
1542
msarett9637ea92016-08-18 14:03:30 -07001543 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001544 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1545 }
1546
1547 // We inline the implementation of mapScaleTranslate() for the fast path.
1548 float sx = fMCRec->fMatrix.getScaleX();
1549 float sy = fMCRec->fMatrix.getScaleY();
1550 float tx = fMCRec->fMatrix.getTranslateX();
1551 float ty = fMCRec->fMatrix.getTranslateY();
1552 Sk4f scale(sx, sy, sx, sy);
1553 Sk4f trans(tx, ty, tx, ty);
1554
1555 // Apply matrix.
1556 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1557
1558 // Make sure left < right, top < bottom.
1559 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1560 Sk4f min = Sk4f::Min(ltrb, rblt);
1561 Sk4f max = Sk4f::Max(ltrb, rblt);
1562 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1563 // ARM this sequence generates the fastest (a single instruction).
1564 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1565
1566 // Check if the device rect is NaN or outside the clip.
1567 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001568}
1569
reed@google.com3b3e8952012-08-16 20:53:31 +00001570bool SkCanvas::quickReject(const SkPath& path) const {
1571 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001572}
1573
Mike Klein83c8dd92017-11-28 17:08:45 -05001574SkRect SkCanvas::getLocalClipBounds() const {
1575 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001576 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001577 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001578 }
1579
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001580 SkMatrix inverse;
1581 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001582 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001583 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001584 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001585
Mike Reed42e8c532017-01-23 14:09:13 -05001586 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001587 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001588 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001589
Mike Reedb57b9312018-04-23 12:12:54 -04001590 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001591 inverse.mapRect(&bounds, r);
1592 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001593}
1594
Mike Klein83c8dd92017-11-28 17:08:45 -05001595SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001596 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001597}
1598
reed@android.com8a1c16f2008-12-17 15:59:43 +00001599const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001600 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001601}
1602
Brian Osman11052242016-10-27 14:47:55 -04001603GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001604 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001605 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001606}
1607
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001608GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001609 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001610 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001611}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001612
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001613void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1614 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001615 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001616 if (outer.isEmpty()) {
1617 return;
1618 }
1619 if (inner.isEmpty()) {
1620 this->drawRRect(outer, paint);
1621 return;
1622 }
1623
1624 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001625 // be able to return ...
1626 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001627 //
1628 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001629 if (!outer.getBounds().contains(inner.getBounds())) {
1630 return;
1631 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001632
1633 this->onDrawDRRect(outer, inner, paint);
1634}
1635
reed41af9662015-01-05 07:49:08 -08001636void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001637 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001638 this->onDrawPaint(paint);
1639}
1640
1641void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001642 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001643 // To avoid redundant logic in our culling code and various backends, we always sort rects
1644 // before passing them along.
1645 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001646}
1647
msarettdca352e2016-08-26 06:37:45 -07001648void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001649 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001650 if (region.isEmpty()) {
1651 return;
1652 }
1653
1654 if (region.isRect()) {
1655 return this->drawIRect(region.getBounds(), paint);
1656 }
1657
1658 this->onDrawRegion(region, paint);
1659}
1660
reed41af9662015-01-05 07:49:08 -08001661void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001662 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001663 // To avoid redundant logic in our culling code and various backends, we always sort rects
1664 // before passing them along.
1665 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001666}
1667
1668void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001669 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001670 this->onDrawRRect(rrect, paint);
1671}
1672
1673void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001674 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001675 this->onDrawPoints(mode, count, pts, paint);
1676}
1677
Mike Reede88a1cb2017-03-17 09:50:46 -04001678void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1679 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001680 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001681 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001682 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1683 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001684 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001685}
1686
1687void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001688 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001689 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001690 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1691}
1692
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001693void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1694 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001695 TRACE_EVENT0("skia", TRACE_FUNC);
1696 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001697 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001698 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1699}
1700
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001701void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1702 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001703 TRACE_EVENT0("skia", TRACE_FUNC);
1704 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001705 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001706 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001707}
1708
1709void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001710 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001711 this->onDrawPath(path, paint);
1712}
1713
reeda85d4d02015-05-06 12:56:48 -07001714void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001715 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001716 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001717 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001718}
1719
Mike Reedc4e31092018-01-30 11:15:27 -05001720// Returns true if the rect can be "filled" : non-empty and finite
1721static bool fillable(const SkRect& r) {
1722 SkScalar w = r.width();
1723 SkScalar h = r.height();
1724 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1725}
1726
reede47829b2015-08-06 10:02:53 -07001727void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1728 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001729 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001730 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001731 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001732 return;
1733 }
1734 this->onDrawImageRect(image, &src, dst, paint, constraint);
1735}
reed41af9662015-01-05 07:49:08 -08001736
reed84984ef2015-07-17 07:09:43 -07001737void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1738 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001739 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001740 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001741}
1742
Brian Salomonf08002c2018-10-26 16:15:46 -04001743void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001744 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001745 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
Brian Salomonf08002c2018-10-26 16:15:46 -04001746 kFast_SrcRectConstraint);
reede47829b2015-08-06 10:02:53 -07001747}
reede47829b2015-08-06 10:02:53 -07001748
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001749namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001750class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001751public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001752 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1753 if (!origPaint) {
1754 return;
1755 }
1756 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1757 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1758 }
1759 if (origPaint->getMaskFilter()) {
1760 fPaint.writable()->setMaskFilter(nullptr);
1761 }
1762 if (origPaint->isAntiAlias()) {
1763 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001764 }
1765 }
1766
1767 const SkPaint* get() const {
1768 return fPaint;
1769 }
1770
1771private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001772 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001773};
1774} // namespace
1775
reed4c21dc52015-06-25 12:32:03 -07001776void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1777 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001778 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001779 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001780 if (dst.isEmpty()) {
1781 return;
1782 }
msarett552bca92016-08-03 06:53:26 -07001783 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001784 LatticePaint latticePaint(paint);
1785 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001786 } else {
reede47829b2015-08-06 10:02:53 -07001787 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001788 }
reed4c21dc52015-06-25 12:32:03 -07001789}
1790
msarett16882062016-08-16 09:31:08 -07001791void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1792 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001793 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001794 RETURN_ON_NULL(image);
1795 if (dst.isEmpty()) {
1796 return;
1797 }
msarett71df2d72016-09-30 12:41:42 -07001798
1799 SkIRect bounds;
1800 Lattice latticePlusBounds = lattice;
1801 if (!latticePlusBounds.fBounds) {
1802 bounds = SkIRect::MakeWH(image->width(), image->height());
1803 latticePlusBounds.fBounds = &bounds;
1804 }
1805
1806 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001807 LatticePaint latticePaint(paint);
1808 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001809 } else {
1810 this->drawImageRect(image, dst, paint);
1811 }
1812}
1813
Brian Salomond7065e72018-10-12 11:42:02 -04001814void SkCanvas::experimental_DrawImageSetV0(const ImageSetEntry imageSet[], int cnt, float alpha,
1815 SkFilterQuality filterQuality, SkBlendMode mode) {
1816 TRACE_EVENT0("skia", TRACE_FUNC);
1817 RETURN_ON_NULL(imageSet);
1818 RETURN_ON_FALSE(cnt);
1819
1820 this->onDrawImageSet(imageSet, cnt, alpha, filterQuality, mode);
1821}
1822
Brian Salomon1da5cad2018-11-21 09:21:18 -05001823void SkCanvas::experimental_DrawImageSetV1(const ImageSetEntry imageSet[], int cnt,
1824 SkFilterQuality filterQuality, SkBlendMode mode) {
1825 TRACE_EVENT0("skia", TRACE_FUNC);
1826 RETURN_ON_NULL(imageSet);
1827 RETURN_ON_FALSE(cnt);
1828
1829 this->onDrawImageSet(imageSet, cnt, 1.f, filterQuality, mode);
1830}
1831
reed41af9662015-01-05 07:49:08 -08001832void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001833 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001834 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001835 return;
1836 }
reed41af9662015-01-05 07:49:08 -08001837 this->onDrawBitmap(bitmap, dx, dy, paint);
1838}
1839
reede47829b2015-08-06 10:02:53 -07001840void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001841 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001842 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001843 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001844 return;
1845 }
reede47829b2015-08-06 10:02:53 -07001846 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001847}
1848
reed84984ef2015-07-17 07:09:43 -07001849void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1850 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001851 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001852}
1853
reede47829b2015-08-06 10:02:53 -07001854void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1855 SrcRectConstraint constraint) {
1856 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1857 constraint);
1858}
reede47829b2015-08-06 10:02:53 -07001859
reed41af9662015-01-05 07:49:08 -08001860void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1861 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001862 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001863 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001864 return;
1865 }
msarett552bca92016-08-03 06:53:26 -07001866 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001867 LatticePaint latticePaint(paint);
1868 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001869 } else {
reeda5517e22015-07-14 10:54:12 -07001870 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001871 }
reed41af9662015-01-05 07:49:08 -08001872}
1873
msarettc573a402016-08-02 08:05:56 -07001874void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1875 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001876 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001877 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001878 return;
1879 }
msarett71df2d72016-09-30 12:41:42 -07001880
1881 SkIRect bounds;
1882 Lattice latticePlusBounds = lattice;
1883 if (!latticePlusBounds.fBounds) {
1884 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1885 latticePlusBounds.fBounds = &bounds;
1886 }
1887
1888 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001889 LatticePaint latticePaint(paint);
1890 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001891 } else {
msarett16882062016-08-16 09:31:08 -07001892 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001893 }
msarettc573a402016-08-02 08:05:56 -07001894}
1895
reed71c3c762015-06-24 10:29:17 -07001896void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001897 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001898 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001899 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001900 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001901 if (count <= 0) {
1902 return;
1903 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001904 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001905 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001906 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001907}
1908
reedf70b5312016-03-04 16:36:20 -08001909void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001910 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001911 if (key) {
1912 this->onDrawAnnotation(rect, key, value);
1913 }
1914}
1915
reede47829b2015-08-06 10:02:53 -07001916void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1917 const SkPaint* paint, SrcRectConstraint constraint) {
1918 if (src) {
1919 this->drawImageRect(image, *src, dst, paint, constraint);
1920 } else {
1921 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1922 dst, paint, constraint);
1923 }
1924}
1925void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1926 const SkPaint* paint, SrcRectConstraint constraint) {
1927 if (src) {
1928 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1929 } else {
1930 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1931 dst, paint, constraint);
1932 }
1933}
1934
Mike Reed4204da22017-05-17 08:53:36 -04001935void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001936 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001937 this->onDrawShadowRec(path, rec);
1938}
1939
1940void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1941 SkPaint paint;
1942 const SkRect& pathBounds = path.getBounds();
1943
Ben Wagner2c312c42018-06-27 14:46:46 -04001944 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001945 while (iter.next()) {
1946 iter.fDevice->drawShadow(path, rec);
1947 }
1948 LOOPER_END
1949}
1950
reed@android.com8a1c16f2008-12-17 15:59:43 +00001951//////////////////////////////////////////////////////////////////////////////
1952// These are the virtual drawing methods
1953//////////////////////////////////////////////////////////////////////////////
1954
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001955void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001956 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001957 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1958 }
1959}
1960
reed41af9662015-01-05 07:49:08 -08001961void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001962 this->internalDrawPaint(paint);
1963}
1964
1965void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04001966 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001967
1968 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001969 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001970 }
1971
reed@google.com4e2b3d32011-04-07 14:18:59 +00001972 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001973}
1974
reed41af9662015-01-05 07:49:08 -08001975void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1976 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001977 if ((long)count <= 0) {
1978 return;
1979 }
1980
Mike Reed822128b2017-02-28 16:41:03 -05001981 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001982 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001983 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001984 // special-case 2 points (common for drawing a single line)
1985 if (2 == count) {
1986 r.set(pts[0], pts[1]);
1987 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001988 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001989 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001990 if (!r.isFinite()) {
1991 return;
1992 }
Mike Reed822128b2017-02-28 16:41:03 -05001993 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001994 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1995 return;
1996 }
1997 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001998 }
reed@google.coma584aed2012-05-16 14:06:02 +00001999
halcanary96fcdcc2015-08-27 07:41:13 -07002000 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002001
Ben Wagner2c312c42018-06-27 14:46:46 -04002002 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002003
reed@android.com8a1c16f2008-12-17 15:59:43 +00002004 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002005 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002006 }
reed@google.com4b226022011-01-11 18:32:13 +00002007
reed@google.com4e2b3d32011-04-07 14:18:59 +00002008 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002009}
2010
reed4a167172016-08-18 17:15:25 -07002011static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2012 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07002013 (intptr_t)paint.getLooper() ) != 0;
2014}
2015
reed41af9662015-01-05 07:49:08 -08002016void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002017 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002018 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002019 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002020 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002021 return;
2022 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002023 }
reed@google.com4b226022011-01-11 18:32:13 +00002024
reed4a167172016-08-18 17:15:25 -07002025 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002026 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002027
reed4a167172016-08-18 17:15:25 -07002028 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002029 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002030 }
2031
2032 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002033 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002034 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002035 SkDrawIter iter(this);
2036 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002037 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002038 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002039 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002040}
2041
msarett44df6512016-08-25 13:54:30 -07002042void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002043 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002044 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002045 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002046 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2047 return;
2048 }
msarett44df6512016-08-25 13:54:30 -07002049 }
2050
Ben Wagner2c312c42018-06-27 14:46:46 -04002051 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002052
2053 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002054 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002055 }
2056
2057 LOOPER_END
2058}
2059
reed41af9662015-01-05 07:49:08 -08002060void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002061 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002062 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002063 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002064 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002065 return;
2066 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002067 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002068
Ben Wagner2c312c42018-06-27 14:46:46 -04002069 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002070
2071 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002072 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002073 }
2074
2075 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002076}
2077
bsalomonac3aa242016-08-19 11:25:19 -07002078void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2079 SkScalar sweepAngle, bool useCenter,
2080 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002081 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002082 if (paint.canComputeFastBounds()) {
2083 SkRect storage;
2084 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002085 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002086 return;
2087 }
bsalomonac3aa242016-08-19 11:25:19 -07002088 }
2089
Ben Wagner2c312c42018-06-27 14:46:46 -04002090 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002091
2092 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002093 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002094 }
2095
2096 LOOPER_END
2097}
2098
reed41af9662015-01-05 07:49:08 -08002099void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002100 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002101 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002102 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2103 return;
2104 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002105 }
2106
2107 if (rrect.isRect()) {
2108 // call the non-virtual version
2109 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002110 return;
2111 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002112 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002113 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2114 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002115 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002116
Ben Wagner2c312c42018-06-27 14:46:46 -04002117 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002118
2119 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002120 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002121 }
2122
2123 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002124}
2125
Mike Reed822128b2017-02-28 16:41:03 -05002126void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002127 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002128 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002129 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2130 return;
2131 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002132 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002133
Ben Wagner2c312c42018-06-27 14:46:46 -04002134 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002135
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002136 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002137 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002138 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002139
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002140 LOOPER_END
2141}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002142
reed41af9662015-01-05 07:49:08 -08002143void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002144 if (!path.isFinite()) {
2145 return;
2146 }
2147
Mike Reed822128b2017-02-28 16:41:03 -05002148 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002149 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002150 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002151 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2152 return;
2153 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002154 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002155
Mike Reed822128b2017-02-28 16:41:03 -05002156 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002157 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002158 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002159 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002160 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002161 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002162
Ben Wagner2c312c42018-06-27 14:46:46 -04002163 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002164
2165 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002166 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002167 }
2168
reed@google.com4e2b3d32011-04-07 14:18:59 +00002169 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002170}
2171
reed262a71b2015-12-05 13:07:27 -08002172bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002173 if (!paint.getImageFilter()) {
2174 return false;
2175 }
2176
2177 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002178 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002179 return false;
2180 }
2181
2182 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2183 // Once we can filter and the filter will return a result larger than itself, we should be
2184 // able to remove this constraint.
2185 // skbug.com/4526
2186 //
2187 SkPoint pt;
2188 ctm.mapXY(x, y, &pt);
2189 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2190 return ir.contains(fMCRec->fRasterClip.getBounds());
2191}
2192
Mike Reedf441cfc2018-04-11 14:50:16 -04002193// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2194// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2195// null.
2196static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2197 if (paintParam) {
2198 *real = *paintParam;
2199 real->setStyle(SkPaint::kFill_Style);
2200 real->setPathEffect(nullptr);
2201 paintParam = real;
2202 }
2203 return paintParam;
2204}
2205
reeda85d4d02015-05-06 12:56:48 -07002206void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002207 SkPaint realPaint;
2208 paint = init_image_paint(&realPaint, paint);
2209
reeda85d4d02015-05-06 12:56:48 -07002210 SkRect bounds = SkRect::MakeXYWH(x, y,
2211 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002212 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002213 SkRect tmp = bounds;
2214 if (paint) {
2215 paint->computeFastBounds(tmp, &tmp);
2216 }
2217 if (this->quickReject(tmp)) {
2218 return;
2219 }
reeda85d4d02015-05-06 12:56:48 -07002220 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002221 // At this point we need a real paint object. If the caller passed null, then we should
2222 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2223 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2224 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002225
reeda2217ef2016-07-20 06:04:34 -07002226 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002227 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2228 *paint);
2229 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002230 special = this->getDevice()->makeSpecial(image);
2231 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002232 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002233 }
2234 }
2235
reed262a71b2015-12-05 13:07:27 -08002236 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2237
reeda85d4d02015-05-06 12:56:48 -07002238 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002239 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002240 if (special) {
2241 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002242 iter.fDevice->ctm().mapXY(x, y, &pt);
2243 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002244 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002245 SkScalarRoundToInt(pt.fY), pnt,
2246 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002247 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002248 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002249 }
reeda85d4d02015-05-06 12:56:48 -07002250 }
halcanary9d524f22016-03-29 09:03:52 -07002251
reeda85d4d02015-05-06 12:56:48 -07002252 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002253}
2254
reed41af9662015-01-05 07:49:08 -08002255void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002256 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002257 SkPaint realPaint;
2258 paint = init_image_paint(&realPaint, paint);
2259
halcanary96fcdcc2015-08-27 07:41:13 -07002260 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002261 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002262 if (paint) {
2263 paint->computeFastBounds(dst, &storage);
2264 }
2265 if (this->quickReject(storage)) {
2266 return;
2267 }
reeda85d4d02015-05-06 12:56:48 -07002268 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002269 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002270
Ben Wagner2c312c42018-06-27 14:46:46 -04002271 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002272
reeda85d4d02015-05-06 12:56:48 -07002273 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002274 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002275 }
halcanary9d524f22016-03-29 09:03:52 -07002276
reeda85d4d02015-05-06 12:56:48 -07002277 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002278}
2279
reed41af9662015-01-05 07:49:08 -08002280void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002281 SkDEBUGCODE(bitmap.validate();)
2282
reed33366972015-10-08 09:22:02 -07002283 if (bitmap.drawsNothing()) {
2284 return;
2285 }
2286
Mike Reedf441cfc2018-04-11 14:50:16 -04002287 SkPaint realPaint;
2288 init_image_paint(&realPaint, paint);
2289 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002290
Mike Reed822128b2017-02-28 16:41:03 -05002291 SkRect bounds;
2292 bitmap.getBounds(&bounds);
2293 bounds.offset(x, y);
2294 bool canFastBounds = paint->canComputeFastBounds();
2295 if (canFastBounds) {
2296 SkRect storage;
2297 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002298 return;
2299 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002300 }
reed@google.com4b226022011-01-11 18:32:13 +00002301
reeda2217ef2016-07-20 06:04:34 -07002302 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002303 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2304 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002305 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002306 special = this->getDevice()->makeSpecial(bitmap);
2307 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002308 drawAsSprite = false;
2309 }
2310 }
2311
Mike Reed822128b2017-02-28 16:41:03 -05002312 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002313
2314 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002315 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002316 if (special) {
reed262a71b2015-12-05 13:07:27 -08002317 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002318 iter.fDevice->ctm().mapXY(x, y, &pt);
2319 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002320 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002321 SkScalarRoundToInt(pt.fY), pnt,
2322 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002323 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002324 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002325 }
reed33366972015-10-08 09:22:02 -07002326 }
msarettfbfa2582016-08-12 08:29:08 -07002327
reed33366972015-10-08 09:22:02 -07002328 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002329}
2330
reed@google.com9987ec32011-09-07 11:57:52 +00002331// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002332void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002333 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002334 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002335 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002336 return;
2337 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002338
halcanary96fcdcc2015-08-27 07:41:13 -07002339 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002340 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002341 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2342 return;
2343 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002344 }
reed@google.com3d608122011-11-21 15:16:16 +00002345
reed@google.com33535f32012-09-25 15:37:50 +00002346 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002347 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002348 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002349 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002350
Ben Wagner2c312c42018-06-27 14:46:46 -04002351 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002352
reed@google.com33535f32012-09-25 15:37:50 +00002353 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002354 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002355 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002356
reed@google.com33535f32012-09-25 15:37:50 +00002357 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002358}
2359
reed41af9662015-01-05 07:49:08 -08002360void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002361 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002362 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002363 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002364}
2365
reed4c21dc52015-06-25 12:32:03 -07002366void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2367 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002368 SkPaint realPaint;
2369 paint = init_image_paint(&realPaint, paint);
2370
halcanary96fcdcc2015-08-27 07:41:13 -07002371 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002372 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002373 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2374 return;
2375 }
reed@google.com3d608122011-11-21 15:16:16 +00002376 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002377 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002378
Ben Wagner2c312c42018-06-27 14:46:46 -04002379 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002380
reed4c21dc52015-06-25 12:32:03 -07002381 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002382 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002383 }
halcanary9d524f22016-03-29 09:03:52 -07002384
reed4c21dc52015-06-25 12:32:03 -07002385 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002386}
2387
reed41af9662015-01-05 07:49:08 -08002388void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2389 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002390 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002391 SkPaint realPaint;
2392 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002393
halcanary96fcdcc2015-08-27 07:41:13 -07002394 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002395 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002396 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2397 return;
2398 }
reed4c21dc52015-06-25 12:32:03 -07002399 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002400 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002401
Ben Wagner2c312c42018-06-27 14:46:46 -04002402 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002403
reed4c21dc52015-06-25 12:32:03 -07002404 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002405 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002406 }
halcanary9d524f22016-03-29 09:03:52 -07002407
reed4c21dc52015-06-25 12:32:03 -07002408 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002409}
2410
msarett16882062016-08-16 09:31:08 -07002411void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2412 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002413 SkPaint realPaint;
2414 paint = init_image_paint(&realPaint, paint);
2415
msarett16882062016-08-16 09:31:08 -07002416 if (nullptr == paint || paint->canComputeFastBounds()) {
2417 SkRect storage;
2418 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2419 return;
2420 }
2421 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002422 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002423
Ben Wagner2c312c42018-06-27 14:46:46 -04002424 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002425
2426 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002427 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002428 }
2429
2430 LOOPER_END
2431}
2432
Brian Salomond7065e72018-10-12 11:42:02 -04002433void SkCanvas::onDrawImageSet(const ImageSetEntry imageSet[], int count, float alpha,
2434 SkFilterQuality filterQuality, SkBlendMode mode) {
2435 SkPaint paint;
2436 LOOPER_BEGIN(paint, nullptr);
2437 while (iter.next()) {
2438 iter.fDevice->drawImageSet(imageSet, count, alpha, filterQuality, mode);
2439 }
2440 LOOPER_END
2441}
2442
msarett16882062016-08-16 09:31:08 -07002443void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2444 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002445 SkPaint realPaint;
2446 paint = init_image_paint(&realPaint, paint);
2447
msarett16882062016-08-16 09:31:08 -07002448 if (nullptr == paint || paint->canComputeFastBounds()) {
2449 SkRect storage;
2450 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2451 return;
2452 }
2453 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002454 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002455
Ben Wagner2c312c42018-06-27 14:46:46 -04002456 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002457
2458 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002459 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002460 }
2461
2462 LOOPER_END
2463}
2464
reed@google.come0d9ce82014-04-23 04:00:17 +00002465void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2466 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002467
Ben Wagner2c312c42018-06-27 14:46:46 -04002468 LOOPER_BEGIN(paint, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002469
2470 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002471 fScratchGlyphRunBuilder->drawText(
Herb Derby4a447432018-06-22 11:45:27 -04002472 looper.paint(), text, byteLength, SkPoint::Make(x, y));
Herb Derby8a6348e2018-07-12 15:30:35 -04002473 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002474 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002475 }
2476
reed@google.com4e2b3d32011-04-07 14:18:59 +00002477 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002478}
2479
reed@google.come0d9ce82014-04-23 04:00:17 +00002480void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2481 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002482
Ben Wagner2c312c42018-06-27 14:46:46 -04002483 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002484
reed@android.com8a1c16f2008-12-17 15:59:43 +00002485 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002486 fScratchGlyphRunBuilder->drawPosText(looper.paint(), text, byteLength, pos);
Herb Derby8a6348e2018-07-12 15:30:35 -04002487 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002488 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002489 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002490
reed@google.com4e2b3d32011-04-07 14:18:59 +00002491 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002492}
2493
reed@google.come0d9ce82014-04-23 04:00:17 +00002494void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2495 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002496
Ben Wagner2c312c42018-06-27 14:46:46 -04002497 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002498
reed@android.com8a1c16f2008-12-17 15:59:43 +00002499 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002500 fScratchGlyphRunBuilder->drawPosTextH(
Herb Derby4a447432018-06-22 11:45:27 -04002501 looper.paint(), text, byteLength, xpos, constY);
Herb Derby8a6348e2018-07-12 15:30:35 -04002502 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002503 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002504 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002505
reed@google.com4e2b3d32011-04-07 14:18:59 +00002506 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002507}
2508
Herb Derby2eacff02018-07-18 13:41:15 -04002509void SkCanvas::onDrawTextRSXform(const void* text, size_t len, const SkRSXform xform[],
reed45561a02016-07-07 12:47:17 -07002510 const SkRect* cullRect, const SkPaint& paint) {
2511 if (cullRect && this->quickReject(*cullRect)) {
2512 return;
2513 }
2514
Ben Wagner2c312c42018-06-27 14:46:46 -04002515 LOOPER_BEGIN(paint, nullptr)
reed45561a02016-07-07 12:47:17 -07002516
2517 while (iter.next()) {
Herb Derby2eacff02018-07-18 13:41:15 -04002518 fScratchGlyphRunBuilder->drawTextAtOrigin(paint, text, len);
2519 auto list = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb935cf82018-07-26 16:54:18 -04002520 if (!list.empty()) {
2521 auto glyphRun = list[0];
Herb Derby2eacff02018-07-18 13:41:15 -04002522 iter.fDevice->drawGlyphRunRSXform(&glyphRun, xform);
2523 }
reed45561a02016-07-07 12:47:17 -07002524 }
2525
2526 LOOPER_END
2527}
2528
fmalita00d5c2c2014-08-21 08:53:26 -07002529void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2530 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002531 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002532 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002533 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002534 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002535 SkRect tmp;
2536 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2537 return;
2538 }
2539 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002540 }
2541
fmalita024f9962015-03-03 19:08:17 -08002542 // We cannot filter in the looper as we normally do, because the paint is
2543 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002544 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002545
fmalitaaa1b9122014-08-28 14:32:24 -07002546 while (iter.next()) {
Herb Derbyb983e6b2018-07-13 13:26:29 -04002547 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, SkPoint::Make(x, y));
2548 iter.fDevice->drawGlyphRunList(fScratchGlyphRunBuilder->useGlyphRunList());
fmalita00d5c2c2014-08-21 08:53:26 -07002549 }
2550
fmalitaaa1b9122014-08-28 14:32:24 -07002551 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002552}
2553
Cary Clark2a475ea2017-04-28 15:35:12 -04002554void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2555 this->drawText(string.c_str(), string.size(), x, y, paint);
2556}
2557
Mike Reed358fcad2018-11-23 15:27:51 -05002558// These call the (virtual) onDraw... method
2559void SkCanvas::drawSimpleText(const void* text, size_t byteLength, SkTextEncoding,
2560 SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
2561 TRACE_EVENT0("skia", TRACE_FUNC);
2562 if (byteLength) {
2563 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
2564 SkPaint tmp(paint);
2565 font.LEGACY_applyToPaint(&tmp);
2566 this->onDrawText(text, byteLength, x, y, tmp);
2567 }
2568}
reed@google.come0d9ce82014-04-23 04:00:17 +00002569void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2570 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002571 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002572 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002573 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002574 this->onDrawText(text, byteLength, x, y, paint);
2575 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002576}
2577void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2578 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002579 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002580 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002581 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002582 this->onDrawPosText(text, byteLength, pos, paint);
2583 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002584}
2585void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2586 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002587 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002588 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002589 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002590 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2591 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002592}
Mike Reed7c8d2e92018-08-27 16:38:05 -04002593
reed45561a02016-07-07 12:47:17 -07002594void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2595 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002596 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002597 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002598 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002599 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2600 }
2601}
fmalita00d5c2c2014-08-21 08:53:26 -07002602void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2603 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002604 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002605 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002606 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002607 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002608}
reed@google.come0d9ce82014-04-23 04:00:17 +00002609
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002610void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002611 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002612 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002613
2614 while (iter.next()) {
2615 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002616 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002617 }
2618
2619 LOOPER_END
2620}
2621
dandovb3c9d1c2014-08-12 08:34:29 -07002622void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002623 const SkPoint texCoords[4], SkBlendMode bmode,
2624 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002625 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002626 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002627 return;
2628 }
mtklein6cfa73a2014-08-13 13:33:49 -07002629
Mike Reedfaba3712016-11-03 14:45:31 -04002630 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002631}
2632
2633void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002634 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002635 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002636 // Since a patch is always within the convex hull of the control points, we discard it when its
2637 // bounding rectangle is completely outside the current clip.
2638 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002639 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002640 if (this->quickReject(bounds)) {
2641 return;
2642 }
mtklein6cfa73a2014-08-13 13:33:49 -07002643
Ben Wagner2c312c42018-06-27 14:46:46 -04002644 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002645
dandovecfff212014-08-04 10:02:00 -07002646 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002647 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002648 }
mtklein6cfa73a2014-08-13 13:33:49 -07002649
dandovecfff212014-08-04 10:02:00 -07002650 LOOPER_END
2651}
2652
reeda8db7282015-07-07 10:22:31 -07002653void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002654#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002655 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002656#endif
reede3b38ce2016-01-08 09:18:44 -08002657 RETURN_ON_NULL(dr);
2658 if (x || y) {
2659 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2660 this->onDrawDrawable(dr, &matrix);
2661 } else {
2662 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002663 }
2664}
2665
reeda8db7282015-07-07 10:22:31 -07002666void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002667#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002668 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002669#endif
reede3b38ce2016-01-08 09:18:44 -08002670 RETURN_ON_NULL(dr);
2671 if (matrix && matrix->isIdentity()) {
2672 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002673 }
reede3b38ce2016-01-08 09:18:44 -08002674 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002675}
2676
2677void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002678 // drawable bounds are no longer reliable (e.g. android displaylist)
2679 // so don't use them for quick-reject
Greg Daniel9ed1a2c2018-10-18 12:43:25 -04002680 this->getDevice()->drawDrawable(dr, matrix, this);
reed6a070dc2014-11-11 19:36:09 -08002681}
2682
reed71c3c762015-06-24 10:29:17 -07002683void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002684 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002685 const SkRect* cull, const SkPaint* paint) {
2686 if (cull && this->quickReject(*cull)) {
2687 return;
2688 }
2689
2690 SkPaint pnt;
2691 if (paint) {
2692 pnt = *paint;
2693 }
halcanary9d524f22016-03-29 09:03:52 -07002694
Ben Wagner2c312c42018-06-27 14:46:46 -04002695 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002696 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002697 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002698 }
2699 LOOPER_END
2700}
2701
reedf70b5312016-03-04 16:36:20 -08002702void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2703 SkASSERT(key);
2704
2705 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002706 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002707 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002708 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002709 }
2710 LOOPER_END
2711}
2712
reed@android.com8a1c16f2008-12-17 15:59:43 +00002713//////////////////////////////////////////////////////////////////////////////
2714// These methods are NOT virtual, and therefore must call back into virtual
2715// methods, rather than actually drawing themselves.
2716//////////////////////////////////////////////////////////////////////////////
2717
reed374772b2016-10-05 17:33:02 -07002718void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002719 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002720 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002721 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002722 this->drawPaint(paint);
2723}
2724
2725void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002726 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2728}
2729
Mike Reed3661bc92017-02-22 13:21:42 -05002730void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002731 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002732 pts[0].set(x0, y0);
2733 pts[1].set(x1, y1);
2734 this->drawPoints(kLines_PointMode, 2, pts, paint);
2735}
2736
Mike Reed3661bc92017-02-22 13:21:42 -05002737void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002738 if (radius < 0) {
2739 radius = 0;
2740 }
2741
2742 SkRect r;
2743 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002744 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002745}
2746
2747void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2748 const SkPaint& paint) {
2749 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002750 SkRRect rrect;
2751 rrect.setRectXY(r, rx, ry);
2752 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753 } else {
2754 this->drawRect(r, paint);
2755 }
2756}
2757
reed@android.com8a1c16f2008-12-17 15:59:43 +00002758void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2759 SkScalar sweepAngle, bool useCenter,
2760 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002761 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002762 if (oval.isEmpty() || !sweepAngle) {
2763 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764 }
bsalomon21af9ca2016-08-25 12:29:23 -07002765 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766}
2767
reed@android.comf76bacf2009-05-13 14:00:33 +00002768///////////////////////////////////////////////////////////////////////////////
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002769#ifdef SK_DISABLE_SKPICTURE
2770void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {}
reed1c2c4412015-04-30 13:09:24 -07002771
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002772
2773void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2774 const SkPaint* paint) {}
2775#else
Mike Klein88d90712018-01-27 17:30:04 +00002776/**
2777 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2778 * against the playback cost of recursing into the subpicture to get at its actual ops.
2779 *
2780 * For now we pick a conservatively small value, though measurement (and other heuristics like
2781 * the type of ops contained) may justify changing this value.
2782 */
2783#define kMaxPictureOpsToUnrollInsteadOfRef 1
2784
reedd5fa1a42014-08-09 11:08:05 -07002785void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002786 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002787 RETURN_ON_NULL(picture);
2788
reede3b38ce2016-01-08 09:18:44 -08002789 if (matrix && matrix->isIdentity()) {
2790 matrix = nullptr;
2791 }
Mike Klein88d90712018-01-27 17:30:04 +00002792 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2793 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2794 picture->playback(this);
2795 } else {
2796 this->onDrawPicture(picture, matrix, paint);
2797 }
reedd5fa1a42014-08-09 11:08:05 -07002798}
robertphillips9b14f262014-06-04 05:40:44 -07002799
reedd5fa1a42014-08-09 11:08:05 -07002800void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2801 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002802 if (!paint || paint->canComputeFastBounds()) {
2803 SkRect bounds = picture->cullRect();
2804 if (paint) {
2805 paint->computeFastBounds(bounds, &bounds);
2806 }
2807 if (matrix) {
2808 matrix->mapRect(&bounds);
2809 }
2810 if (this->quickReject(bounds)) {
2811 return;
2812 }
2813 }
2814
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002815 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002816 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817}
Kevin Lubick32dfdbe2018-10-18 09:47:01 -04002818#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002819
reed@android.com8a1c16f2008-12-17 15:59:43 +00002820///////////////////////////////////////////////////////////////////////////////
2821///////////////////////////////////////////////////////////////////////////////
2822
reed3aafe112016-08-18 12:45:34 -07002823SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002824 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002825
2826 SkASSERT(canvas);
2827
reed3aafe112016-08-18 12:45:34 -07002828 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002829 fDone = !fImpl->next();
2830}
2831
2832SkCanvas::LayerIter::~LayerIter() {
2833 fImpl->~SkDrawIter();
2834}
2835
2836void SkCanvas::LayerIter::next() {
2837 fDone = !fImpl->next();
2838}
2839
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002840SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002841 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842}
2843
2844const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002845 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002846}
2847
2848const SkPaint& SkCanvas::LayerIter::paint() const {
2849 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002850 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002851 paint = &fDefaultPaint;
2852 }
2853 return *paint;
2854}
2855
Mike Reedca37f322018-03-08 13:22:16 -05002856SkIRect SkCanvas::LayerIter::clipBounds() const {
2857 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002858}
2859
reed@android.com8a1c16f2008-12-17 15:59:43 +00002860int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2861int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002862
2863///////////////////////////////////////////////////////////////////////////////
2864
Mike Reed5df49342016-11-12 08:06:55 -06002865std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002866 size_t rowBytes, const SkSurfaceProps* props) {
Brian Osman431ac562018-10-10 13:20:38 -04002867 if (!SkSurfaceValidateRasterInfo(info, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002868 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002869 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002870
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002871 SkBitmap bitmap;
2872 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002873 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002874 }
Mike Reed12f77342017-11-08 11:19:52 -05002875
2876 return props ?
2877 skstd::make_unique<SkCanvas>(bitmap, *props) :
2878 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002879}
reedd5fa1a42014-08-09 11:08:05 -07002880
2881///////////////////////////////////////////////////////////////////////////////
2882
Florin Malitaee424ac2016-12-01 12:47:59 -05002883SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002884 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002885
Florin Malita439ace92016-12-02 12:05:41 -05002886SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002887 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002888
Herb Derbyefe39bc2018-05-01 17:06:20 -04002889SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002890 : INHERITED(device) {}
2891
Florin Malitaee424ac2016-12-01 12:47:59 -05002892SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2893 (void)this->INHERITED::getSaveLayerStrategy(rec);
2894 return kNoLayer_SaveLayerStrategy;
2895}
2896
2897///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002898
reed73603f32016-09-20 08:42:38 -07002899static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2900static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2901static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2902static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2903static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2904static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002905
2906///////////////////////////////////////////////////////////////////////////////////////////////////
2907
2908SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2909 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002910 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002911 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2912 SkIPoint origin = dev->getOrigin();
2913 SkMatrix ctm = this->getTotalMatrix();
2914 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2915
2916 SkIRect clip = fMCRec->fRasterClip.getBounds();
2917 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002918 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002919 clip.setEmpty();
2920 }
2921
2922 fAllocator->updateHandle(handle, ctm, clip);
2923 return handle;
2924 }
2925 return nullptr;
2926}
2927
2928static bool install(SkBitmap* bm, const SkImageInfo& info,
2929 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002930 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002931}
2932
2933SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2934 SkBitmap* bm) {
2935 SkRasterHandleAllocator::Rec rec;
2936 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2937 return nullptr;
2938 }
2939 return rec.fHandle;
2940}
2941
2942std::unique_ptr<SkCanvas>
2943SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2944 const SkImageInfo& info, const Rec* rec) {
Brian Osman431ac562018-10-10 13:20:38 -04002945 if (!alloc || !SkSurfaceValidateRasterInfo(info, rec ? rec->fRowBytes : kIgnoreRowBytesValue)) {
Mike Reed356f7c22017-01-10 11:58:39 -05002946 return nullptr;
2947 }
2948
2949 SkBitmap bm;
2950 Handle hndl;
2951
2952 if (rec) {
2953 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2954 } else {
2955 hndl = alloc->allocBitmap(info, &bm);
2956 }
2957 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2958}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002959
2960///////////////////////////////////////////////////////////////////////////////////////////////////
2961
2962