blob: ff8afaabec9ecda4e5f90174ab633e84957cdce8 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Hal Canaryc640d0d2018-06-13 09:59:02 -04008#include "SkCanvas.h"
9
Herb Derby73fe7b02017-02-08 15:12:19 -050010#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +000011#include "SkBitmapDevice.h"
reedd5fa1a42014-08-09 11:08:05 -070012#include "SkCanvasPriv.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040013#include "SkClipOpPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070014#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070015#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDraw.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#include "SkDrawLooper.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040018#include "SkDrawable.h"
Herb Derby41f4f312018-06-06 17:45:53 +000019#include "SkGlyphCache.h"
20#include "SkGlyphRun.h"
piotaixrb5fae932014-09-24 13:03:30 -070021#include "SkImage.h"
senorblanco900c3672016-04-27 11:31:23 -070022#include "SkImageFilter.h"
23#include "SkImageFilterCache.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040024#include "SkImage_Base.h"
msarettc573a402016-08-02 08:05:56 -070025#include "SkLatticeIter.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040026#include "SkMSAN.h"
Mike Reed5df49342016-11-12 08:06:55 -060027#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080028#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000029#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050030#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070031#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070032#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070033#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040034#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000035#include "SkPicture.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040036#include "SkRRect.h"
reed@google.com00177082011-10-12 14:34:30 +000037#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050038#include "SkRasterHandleAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080039#include "SkSpecialImage.h"
Herb Derby41f4f312018-06-06 17:45:53 +000040#include "SkStrikeCache.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040041#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000042#include "SkSurface_Base.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040043#include "SkTLazy.h"
fmalita7ba7aa72014-08-29 09:46:36 -070044#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000045#include "SkTextFormatParams.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040046#include "SkTo.h"
danakj8f757f52014-11-04 11:48:43 -080047#include "SkTraceEvent.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040048#include "SkVertices.h"
49
bungemand3ebb482015-08-05 13:57:49 -070050#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000051
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080053#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050054#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000055#endif
56
reede3b38ce2016-01-08 09:18:44 -080057#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050058#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080059
Mike Reed139e5e02017-03-08 11:29:33 -050060///////////////////////////////////////////////////////////////////////////////////////////////////
61
reedc83a2972015-07-16 07:40:45 -070062/*
63 * Return true if the drawing this rect would hit every pixels in the canvas.
64 *
65 * Returns false if
66 * - rect does not contain the canvas' bounds
67 * - paint is not fill
68 * - paint would blur or otherwise change the coverage of the rect
69 */
70bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
71 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070072 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
73 (int)kNone_ShaderOverrideOpacity,
74 "need_matching_enums0");
75 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
76 (int)kOpaque_ShaderOverrideOpacity,
77 "need_matching_enums1");
78 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
79 (int)kNotOpaque_ShaderOverrideOpacity,
80 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070081
82 const SkISize size = this->getBaseLayerSize();
83 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050084
85 // if we're clipped at all, we can't overwrite the entire surface
86 {
87 SkBaseDevice* base = this->getDevice();
88 SkBaseDevice* top = this->getTopDevice();
89 if (base != top) {
90 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
91 }
92 if (!base->clipIsWideOpen()) {
93 return false;
94 }
reedc83a2972015-07-16 07:40:45 -070095 }
96
97 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070098 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070099 return false; // conservative
100 }
halcanaryc5769b22016-08-10 07:13:21 -0700101
102 SkRect devRect;
103 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
104 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700105 return false;
106 }
107 }
108
109 if (paint) {
110 SkPaint::Style paintStyle = paint->getStyle();
111 if (!(paintStyle == SkPaint::kFill_Style ||
112 paintStyle == SkPaint::kStrokeAndFill_Style)) {
113 return false;
114 }
115 if (paint->getMaskFilter() || paint->getLooper()
116 || paint->getPathEffect() || paint->getImageFilter()) {
117 return false; // conservative
118 }
119 }
120 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
121}
122
123///////////////////////////////////////////////////////////////////////////////////////////////////
124
reed@google.comda17f752012-08-16 18:27:05 +0000125// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126//#define SK_TRACE_SAVERESTORE
127
128#ifdef SK_TRACE_SAVERESTORE
129 static int gLayerCounter;
130 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
131 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
132
133 static int gRecCounter;
134 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
135 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
136
137 static int gCanvasCounter;
138 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
139 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
140#else
141 #define inc_layer()
142 #define dec_layer()
143 #define inc_rec()
144 #define dec_rec()
145 #define inc_canvas()
146 #define dec_canvas()
147#endif
148
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000149typedef SkTLazy<SkPaint> SkLazyPaint;
150
reedc83a2972015-07-16 07:40:45 -0700151void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000152 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700153 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
154 ? SkSurface::kDiscard_ContentChangeMode
155 : SkSurface::kRetain_ContentChangeMode);
156 }
157}
158
159void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
160 ShaderOverrideOpacity overrideOpacity) {
161 if (fSurfaceBase) {
162 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
163 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
164 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
165 // and therefore we don't care which mode we're in.
166 //
167 if (fSurfaceBase->outstandingImageSnapshot()) {
168 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
169 mode = SkSurface::kDiscard_ContentChangeMode;
170 }
171 }
172 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000173 }
174}
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000178/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 The clip/matrix/proc are fields that reflect the top of the save/restore
180 stack. Whenever the canvas changes, it marks a dirty flag, and then before
181 these are used (assuming we're not on a layer) we rebuild these cache
182 values: they reflect the top of the save stack, but translated and clipped
183 by the device's XY offset and bitmap-bounds.
184*/
185struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400186 DeviceCM* fNext;
187 sk_sp<SkBaseDevice> fDevice;
188 SkRasterClip fClip;
189 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
190 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400191 sk_sp<SkImage> fClipImage;
192 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193
Florin Malita53f77bd2017-04-28 13:48:37 -0400194 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000195 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700196 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400197 , fDevice(std::move(device))
198 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700199 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000200 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400201 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400202 {}
reed@google.com4b226022011-01-11 18:32:13 +0000203
mtkleinfeaadee2015-04-08 11:25:48 -0700204 void reset(const SkIRect& bounds) {
205 SkASSERT(!fPaint);
206 SkASSERT(!fNext);
207 SkASSERT(fDevice);
208 fClip.setRect(bounds);
209 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210};
211
212/* This is the record we keep for each save/restore level in the stack.
213 Since a level optionally copies the matrix and/or stack, we have pointers
214 for these fields. If the value is copied for this level, the copy is
215 stored in the ...Storage field, and the pointer points to that. If the
216 value is not copied for this level, we ignore ...Storage, and just point
217 at the corresponding value in the previous level in the stack.
218*/
219class SkCanvas::MCRec {
220public:
reedd9544982014-09-09 18:46:22 -0700221 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 /* If there are any layers in the stack, this points to the top-most
223 one that is at or below this level in the stack (so we know what
224 bitmap/device to draw into from this level. This value is NOT
225 reference counted, since the real owner is either our fLayer field,
226 or a previous one in a lower level.)
227 */
Mike Reeda1361362017-03-07 09:37:29 -0500228 DeviceCM* fTopLayer;
229 SkConservativeClip fRasterClip;
230 SkMatrix fMatrix;
231 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232
Mike Reeda1361362017-03-07 09:37:29 -0500233 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700234 fLayer = nullptr;
235 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800236 fMatrix.reset();
237 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700238
reedd9544982014-09-09 18:46:22 -0700239 // don't bother initializing fNext
240 inc_rec();
241 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400242 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700243 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700244 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800245 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700246
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 // don't bother initializing fNext
248 inc_rec();
249 }
250 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700251 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 dec_rec();
253 }
mtkleinfeaadee2015-04-08 11:25:48 -0700254
255 void reset(const SkIRect& bounds) {
256 SkASSERT(fLayer);
257 SkASSERT(fDeferredSaveCount == 0);
258
259 fMatrix.reset();
260 fRasterClip.setRect(bounds);
261 fLayer->reset(bounds);
262 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263};
264
Mike Reeda1361362017-03-07 09:37:29 -0500265class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266public:
Mike Reeda1361362017-03-07 09:37:29 -0500267 SkDrawIter(SkCanvas* canvas)
268 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
269 {}
reed@google.com4b226022011-01-11 18:32:13 +0000270
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000272 const DeviceCM* rec = fCurrLayer;
273 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400274 fDevice = rec->fDevice.get();
275 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700277 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 return true;
279 }
280 return false;
281 }
reed@google.com4b226022011-01-11 18:32:13 +0000282
reed@google.com6f8f2922011-03-04 22:27:10 +0000283 int getX() const { return fDevice->getOrigin().x(); }
284 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000286
Mike Reed99330ba2017-02-22 11:01:08 -0500287 SkBaseDevice* fDevice;
288
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 const DeviceCM* fCurrLayer;
291 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292};
293
Florin Malita713b8ef2017-04-28 10:57:24 -0400294#define FOR_EACH_TOP_DEVICE( code ) \
295 do { \
296 DeviceCM* layer = fMCRec->fTopLayer; \
297 while (layer) { \
298 SkBaseDevice* device = layer->fDevice.get(); \
299 if (device) { \
300 code; \
301 } \
302 layer = layer->fNext; \
303 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500304 } while (0)
305
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306/////////////////////////////////////////////////////////////////////////////
307
reeddbc3cef2015-04-29 12:18:57 -0700308static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
309 return lazy->isValid() ? lazy->get() : lazy->set(orig);
310}
311
312/**
313 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700314 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700315 */
reedd053ce92016-03-22 10:17:23 -0700316static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700317 SkImageFilter* imgf = paint.getImageFilter();
318 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700319 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700320 }
321
reedd053ce92016-03-22 10:17:23 -0700322 SkColorFilter* imgCFPtr;
323 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700324 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700325 }
reedd053ce92016-03-22 10:17:23 -0700326 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700327
328 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700329 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700330 // there is no existing paint colorfilter, so we can just return the imagefilter's
331 return imgCF;
332 }
333
334 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
335 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500336 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700337}
338
senorblanco87e066e2015-10-28 11:23:36 -0700339/**
340 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
341 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
342 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
343 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
344 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
345 * conservative "effective" bounds based on the settings in the paint... with one exception. This
346 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
347 * deliberately ignored.
348 */
349static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
350 const SkRect& rawBounds,
351 SkRect* storage) {
352 SkPaint tmpUnfiltered(paint);
353 tmpUnfiltered.setImageFilter(nullptr);
354 if (tmpUnfiltered.canComputeFastBounds()) {
355 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
356 } else {
357 return rawBounds;
358 }
359}
360
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361class AutoDrawLooper {
362public:
senorblanco87e066e2015-10-28 11:23:36 -0700363 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
364 // paint. It's used to determine the size of the offscreen layer for filters.
365 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700366 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700367 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000368 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700369 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000370 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700371 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000372 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373
reedd053ce92016-03-22 10:17:23 -0700374 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700375 if (simplifiedCF) {
376 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700377 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700378 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700379 fPaint = paint;
380 }
381
382 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700383 /**
384 * We implement ImageFilters for a given draw by creating a layer, then applying the
385 * imagefilter to the pixels of that layer (its backing surface/image), and then
386 * we call restore() to xfer that layer to the main canvas.
387 *
388 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
389 * 2. Generate the src pixels:
390 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
391 * return (fPaint). We then draw the primitive (using srcover) into a cleared
392 * buffer/surface.
393 * 3. Restore the layer created in #1
394 * The imagefilter is passed the buffer/surface from the layer (now filled with the
395 * src pixels of the primitive). It returns a new "filtered" buffer, which we
396 * draw onto the previous layer using the xfermode from the original paint.
397 */
reed@google.com8926b162012-03-23 15:36:36 +0000398 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500399 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700400 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700401 SkRect storage;
402 if (rawBounds) {
403 // Make rawBounds include all paint outsets except for those due to image filters.
404 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
405 }
reedbfd5f172016-01-07 11:28:08 -0800406 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700407 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700408 fTempLayerForImageFilter = true;
409 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000410 }
411
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000412 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500413 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000414 fIsSimple = false;
415 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700416 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000417 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400418 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000419 }
420 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000421
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700423 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000424 fCanvas->internalRestore();
425 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000426 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000428
reed@google.com4e2b3d32011-04-07 14:18:59 +0000429 const SkPaint& paint() const {
430 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400431 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000432 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000434
Ben Wagner2c312c42018-06-27 14:46:46 -0400435 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000436 if (fDone) {
437 return false;
438 } else if (fIsSimple) {
439 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000440 return !fPaint->nothingToDraw();
441 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400442 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000443 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000444 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000445
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500447 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700448 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000449 SkCanvas* fCanvas;
450 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000451 const SkPaint* fPaint;
452 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700453 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000454 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000455 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000456 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400457 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000458
Ben Wagner2c312c42018-06-27 14:46:46 -0400459 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460};
461
Ben Wagner2c312c42018-06-27 14:46:46 -0400462bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700463 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000464 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400465 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000466
reeddbc3cef2015-04-29 12:18:57 -0700467 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
468 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400469 // never want our downstream clients (i.e. devices) to see loopers
470 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000471
reed5c476fb2015-04-20 08:04:21 -0700472 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700473 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700474 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000475 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000476
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000477 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000478 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000479 return false;
480 }
reed@google.com129ec222012-05-15 13:24:09 +0000481 fPaint = paint;
482
483 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400484 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000485 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000486 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000487 return true;
488}
489
reed@android.com8a1c16f2008-12-17 15:59:43 +0000490////////// macros to place around the internal draw calls //////////////////
491
reed3aafe112016-08-18 12:45:34 -0700492#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
493 this->predrawNotify(); \
494 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400495 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800496 SkDrawIter iter(this);
497
498
Ben Wagner2c312c42018-06-27 14:46:46 -0400499#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000500 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700501 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400502 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000503 SkDrawIter iter(this);
504
Ben Wagner2c312c42018-06-27 14:46:46 -0400505#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000506 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700507 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400508 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000510
Ben Wagner2c312c42018-06-27 14:46:46 -0400511#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700512 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700513 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400514 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700515 SkDrawIter iter(this);
516
reed@google.com4e2b3d32011-04-07 14:18:59 +0000517#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000518
519////////////////////////////////////////////////////////////////////////////
520
msarettfbfa2582016-08-12 08:29:08 -0700521static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
522 if (bounds.isEmpty()) {
523 return SkRect::MakeEmpty();
524 }
525
526 // Expand bounds out by 1 in case we are anti-aliasing. We store the
527 // bounds as floats to enable a faster quick reject implementation.
528 SkRect dst;
529 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
530 return dst;
531}
532
mtkleinfeaadee2015-04-08 11:25:48 -0700533void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
534 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700535 fMCRec->reset(bounds);
536
537 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500538 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400539 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700540 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700541 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700542}
543
Herb Derbyefe39bc2018-05-01 17:06:20 -0400544void SkCanvas::init(sk_sp<SkBaseDevice> device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800545 if (device && device->forceConservativeRasterClip()) {
546 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
547 }
reed42b73eb2015-11-20 13:42:42 -0800548
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000549 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800550 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700551 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552
553 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500554 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500555 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700556 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000557
reeda499f902015-05-01 09:34:31 -0700558 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
559 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400560 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700561
reed@android.com8a1c16f2008-12-17 15:59:43 +0000562 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563
halcanary96fcdcc2015-08-27 07:41:13 -0700564 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000565
reedf92c8662014-08-18 08:02:43 -0700566 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700567 // The root device and the canvas should always have the same pixel geometry
568 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800569 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700570 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500571
Mike Reedc42a1cd2017-02-14 14:25:14 -0500572 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700573 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400574
Herb Derby59d997a2018-06-07 12:44:09 -0400575 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576}
577
reed@google.comcde92112011-07-06 20:00:52 +0000578SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000579 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700580 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000581{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000582 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000583
halcanary96fcdcc2015-08-27 07:41:13 -0700584 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000585}
586
reed96a857e2015-01-25 10:33:58 -0800587SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000588 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800589 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000590{
591 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400592 this->init(sk_make_sp<SkNoPixelsDevice>(
593 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps), kDefault_InitFlags);
reedd9544982014-09-09 18:46:22 -0700594}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000595
reed78e27682014-11-19 08:04:34 -0800596SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700597 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700598 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700599{
600 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700601
Mike Reed566e53c2017-03-10 10:49:45 -0500602 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400603 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps), flags);
reedd9544982014-09-09 18:46:22 -0700604}
605
Herb Derbyefe39bc2018-05-01 17:06:20 -0400606SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000607 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700608 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000609{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000610 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700611
reedd9544982014-09-09 18:46:22 -0700612 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000613}
614
Herb Derbyefe39bc2018-05-01 17:06:20 -0400615SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device, InitFlags flags)
robertphillipsfcf78292015-06-19 11:49:52 -0700616 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700617 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700618{
619 inc_canvas();
620
621 this->init(device, flags);
622}
623
reed4a8126e2014-09-22 07:29:03 -0700624SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700625 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700626 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700627{
628 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700629
Mike Reed910ca0f2018-04-25 13:04:05 -0400630 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400631 this->init(device, kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700632}
reed29c857d2014-09-21 10:25:07 -0700633
Mike Reed356f7c22017-01-10 11:58:39 -0500634SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
635 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700636 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
637 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500638 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700639{
640 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700641
Mike Reed910ca0f2018-04-25 13:04:05 -0400642 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400643 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644}
645
Mike Reed356f7c22017-01-10 11:58:39 -0500646SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
647
Matt Sarett31f99ce2017-04-11 08:46:01 -0400648#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
649SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
650 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
651 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
652 , fAllocator(nullptr)
653{
654 inc_canvas();
655
656 SkBitmap tmp(bitmap);
657 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400658 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Herb Derbyefe39bc2018-05-01 17:06:20 -0400659 this->init(device, kDefault_InitFlags);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400660}
661#endif
662
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663SkCanvas::~SkCanvas() {
664 // free up the contents of our deque
665 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000666
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667 this->internalRestore(); // restore the last, since we're going away
668
halcanary385fe4d2015-08-26 13:07:48 -0700669 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000670
reed@android.com8a1c16f2008-12-17 15:59:43 +0000671 dec_canvas();
672}
673
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000674SkMetaData& SkCanvas::getMetaData() {
675 // metadata users are rare, so we lazily allocate it. If that changes we
676 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700677 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000678 fMetaData = new SkMetaData;
679 }
680 return *fMetaData;
681}
682
reed@android.com8a1c16f2008-12-17 15:59:43 +0000683///////////////////////////////////////////////////////////////////////////////
684
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000685void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700686 this->onFlush();
687}
688
689void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000690 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000691 if (device) {
692 device->flush();
693 }
694}
695
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000696SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000697 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000698 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
699}
700
senorblancoafc7cce2016-02-02 18:44:15 -0800701SkIRect SkCanvas::getTopLayerBounds() const {
702 SkBaseDevice* d = this->getTopDevice();
703 if (!d) {
704 return SkIRect::MakeEmpty();
705 }
706 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
707}
708
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000709SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000710 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000711 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000712 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400713 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000714}
715
Florin Malita0ed3b642017-01-13 16:56:38 +0000716SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400717 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000718}
719
Mike Reed353196f2017-07-21 11:01:18 -0400720bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000721 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400722 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000723}
724
Mike Reed353196f2017-07-21 11:01:18 -0400725bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
726 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400727}
728
729bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
730 SkPixmap pm;
731 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
732}
733
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000734bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400735 SkPixmap pm;
736 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700737 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000738 }
739 return false;
740}
741
Matt Sarett03dd6d52017-01-23 12:15:09 -0500742bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000743 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000744 SkBaseDevice* device = this->getDevice();
745 if (!device) {
746 return false;
747 }
748
Matt Sarett03dd6d52017-01-23 12:15:09 -0500749 // This check gives us an early out and prevents generation ID churn on the surface.
750 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
751 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
752 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
753 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000754 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000755
Matt Sarett03dd6d52017-01-23 12:15:09 -0500756 // Tell our owning surface to bump its generation ID.
757 const bool completeOverwrite =
758 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700759 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700760
Matt Sarett03dd6d52017-01-23 12:15:09 -0500761 // This can still fail, most notably in the case of a invalid color type or alpha type
762 // conversion. We could pull those checks into this function and avoid the unnecessary
763 // generation ID bump. But then we would be performing those checks twice, since they
764 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400765 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000766}
reed@google.com51df9e32010-12-23 19:29:18 +0000767
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768//////////////////////////////////////////////////////////////////////////////
769
reed2ff1fce2014-12-11 07:07:37 -0800770void SkCanvas::checkForDeferredSave() {
771 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800772 this->doSave();
773 }
774}
775
reedf0090cb2014-11-26 08:55:51 -0800776int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800777#ifdef SK_DEBUG
778 int count = 0;
779 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
780 for (;;) {
781 const MCRec* rec = (const MCRec*)iter.next();
782 if (!rec) {
783 break;
784 }
785 count += 1 + rec->fDeferredSaveCount;
786 }
787 SkASSERT(count == fSaveCount);
788#endif
789 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800790}
791
792int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800793 fSaveCount += 1;
794 fMCRec->fDeferredSaveCount += 1;
795 return this->getSaveCount() - 1; // return our prev value
796}
797
798void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800799 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700800
801 SkASSERT(fMCRec->fDeferredSaveCount > 0);
802 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800803 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800804}
805
806void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800807 if (fMCRec->fDeferredSaveCount > 0) {
808 SkASSERT(fSaveCount > 1);
809 fSaveCount -= 1;
810 fMCRec->fDeferredSaveCount -= 1;
811 } else {
812 // check for underflow
813 if (fMCStack.count() > 1) {
814 this->willRestore();
815 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700816 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800817 this->internalRestore();
818 this->didRestore();
819 }
reedf0090cb2014-11-26 08:55:51 -0800820 }
821}
822
823void SkCanvas::restoreToCount(int count) {
824 // sanity check
825 if (count < 1) {
826 count = 1;
827 }
mtkleinf0f14112014-12-12 08:46:25 -0800828
reedf0090cb2014-11-26 08:55:51 -0800829 int n = this->getSaveCount() - count;
830 for (int i = 0; i < n; ++i) {
831 this->restore();
832 }
833}
834
reed2ff1fce2014-12-11 07:07:37 -0800835void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700837 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000838 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000839
Mike Reedc42a1cd2017-02-14 14:25:14 -0500840 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000841}
842
reed4960eee2015-12-18 07:09:18 -0800843bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400844 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845}
846
reed4960eee2015-12-18 07:09:18 -0800847bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700848 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500849 SkIRect clipBounds = this->getDeviceClipBounds();
850 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000851 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000852 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000853
reed96e657d2015-03-10 17:30:07 -0700854 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
855
Robert Phillips12078432018-05-17 11:17:39 -0400856 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
857 // If the image filter DAG affects transparent black then we will need to render
858 // out to the clip bounds
859 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000860 }
Robert Phillips12078432018-05-17 11:17:39 -0400861
862 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700863 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000864 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700865 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400866 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400868 inputSaveLayerBounds = clipBounds;
869 }
870
871 if (imageFilter) {
872 // expand the clip bounds by the image filter DAG to include extra content that might
873 // be required by the image filters.
874 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
875 SkImageFilter::kReverse_MapDirection,
876 &inputSaveLayerBounds);
877 }
878
879 SkIRect clippedSaveLayerBounds;
880 if (bounds) {
881 // For better or for worse, user bounds currently act as a hard clip on the layer's
882 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
883 clippedSaveLayerBounds = inputSaveLayerBounds;
884 } else {
885 // If there are no user bounds, we don't want to artificially restrict the resulting
886 // layer bounds, so allow the expanded clip bounds free reign.
887 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000888 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800889
890 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400891 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800892 if (BoundsAffectsClip(saveLayerFlags)) {
893 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
894 fMCRec->fRasterClip.setEmpty();
895 fDeviceClipBounds.setEmpty();
896 }
897 return false;
898 }
Robert Phillips12078432018-05-17 11:17:39 -0400899 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000900
reed4960eee2015-12-18 07:09:18 -0800901 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700902 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400903 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
904 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000905 }
906
907 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400908 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000909 }
Robert Phillips12078432018-05-17 11:17:39 -0400910
junov@chromium.orga907ac32012-02-24 21:54:07 +0000911 return true;
912}
913
reed4960eee2015-12-18 07:09:18 -0800914int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
915 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000916}
917
reed70ee31b2015-12-10 13:44:45 -0800918int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800919 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
920}
921
Cary Clarke041e312018-03-06 13:00:52 -0500922int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Mike Reed49f8da02018-08-27 10:48:52 -0400923 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
924 // no need for the layer (or any of the draws until the matching restore()
925 this->save();
926 this->clipRect({0,0,0,0});
927 } else {
928 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
929 fSaveCount += 1;
930 this->internalSaveLayer(rec, strategy);
931 }
reed4960eee2015-12-18 07:09:18 -0800932 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800933}
934
reeda2217ef2016-07-20 06:04:34 -0700935void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500936 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500937 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700938 SkDraw draw;
939 SkRasterClip rc;
940 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
941 if (!dst->accessPixels(&draw.fDst)) {
942 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800943 }
reeda2217ef2016-07-20 06:04:34 -0700944 draw.fMatrix = &SkMatrix::I();
945 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800946
947 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500948 if (filter) {
949 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
950 }
reeda2217ef2016-07-20 06:04:34 -0700951
Mike Reedc42a1cd2017-02-14 14:25:14 -0500952 int x = src->getOrigin().x() - dstOrigin.x();
953 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700954 auto special = src->snapSpecial();
955 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400956 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700957 }
robertphillips7354a4b2015-12-16 05:08:27 -0800958}
reed70ee31b2015-12-10 13:44:45 -0800959
Mike Kleine083f7c2018-02-07 12:54:27 -0500960static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500961 // Need to force L32 for now if we have an image filter.
962 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
963 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500964 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800965 }
Mike Klein649fb732018-02-26 15:09:16 -0500966
967 SkColorType ct = prev.colorType();
968 if (prev.bytesPerPixel() <= 4) {
969 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
970 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
971 ct = kN32_SkColorType;
972 }
973 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800974}
975
reed4960eee2015-12-18 07:09:18 -0800976void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
977 const SkRect* bounds = rec.fBounds;
978 const SkPaint* paint = rec.fPaint;
979 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
980
reed8c30a812016-04-20 16:36:51 -0700981 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400982 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700983 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400984 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700985 SkMatrix remainder;
986 SkSize scale;
987 /*
988 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
989 * but they do handle scaling. To accommodate this, we do the following:
990 *
991 * 1. Stash off the current CTM
992 * 2. Decompose the CTM into SCALE and REMAINDER
993 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
994 * contains the REMAINDER
995 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
996 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
997 * of the original imagefilter, and draw that (via drawSprite)
998 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
999 *
1000 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1001 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1002 */
reed96a04f32016-04-25 09:25:15 -07001003 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001004 stashedMatrix.decomposeScale(&scale, &remainder))
1005 {
1006 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001007 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001008 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1009 SkPaint* p = lazyP.set(*paint);
1010 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1011 SkFilterQuality::kLow_SkFilterQuality,
1012 sk_ref_sp(imageFilter)));
1013 imageFilter = p->getImageFilter();
1014 paint = p;
1015 }
reed8c30a812016-04-20 16:36:51 -07001016
junov@chromium.orga907ac32012-02-24 21:54:07 +00001017 // do this before we create the layer. We don't call the public save() since
1018 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001019 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001020
junov@chromium.orga907ac32012-02-24 21:54:07 +00001021 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001022 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001023 if (modifiedRec) {
1024 // In this case there will be no layer in which to stash the matrix so we need to
1025 // revert the prior MCRec to its earlier state.
1026 modifiedRec->fMatrix = stashedMatrix;
1027 }
reed2ff1fce2014-12-11 07:07:37 -08001028 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029 }
1030
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001031 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1032 // the clipRectBounds() call above?
1033 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001034 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001035 }
1036
reed8dc0ccb2015-03-20 06:32:52 -07001037 SkPixelGeometry geo = fProps.pixelGeometry();
1038 if (paint) {
reed76033be2015-03-14 10:54:31 -07001039 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001040 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001041 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001042 }
1043 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001044
robertphillips5139e502016-07-19 05:10:40 -07001045 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001046 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001047 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001048 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001049 }
reedb2db8982014-11-13 12:41:02 -08001050
Mike Kleine083f7c2018-02-07 12:54:27 -05001051 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001052
Hal Canary704cd322016-11-07 14:13:52 -05001053 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001054 {
reed70ee31b2015-12-10 13:44:45 -08001055 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001056 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001057 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001058 const bool trackCoverage =
1059 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001060 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001061 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001062 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001063 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001064 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1065 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001066 return;
reed61f501f2015-04-29 08:34:00 -07001067 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001068 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001069 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001070
Mike Reedb43a3e02017-02-11 10:18:58 -05001071 // only have a "next" if this new layer doesn't affect the clip (rare)
1072 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001073 fMCRec->fLayer = layer;
1074 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001075
Mike Reedc61abee2017-02-28 17:45:27 -05001076 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001077 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001078 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001079 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001080
Mike Reedc42a1cd2017-02-14 14:25:14 -05001081 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1082
1083 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1084 if (layer->fNext) {
1085 // need to punch a hole in the previous device, so we don't draw there, given that
1086 // the new top-layer will allow drawing to happen "below" it.
1087 SkRegion hole(ir);
1088 do {
1089 layer = layer->fNext;
1090 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1091 } while (layer->fNext);
1092 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093}
1094
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001095int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001096 if (0xFF == alpha) {
1097 return this->saveLayer(bounds, nullptr);
1098 } else {
1099 SkPaint tmpPaint;
1100 tmpPaint.setAlpha(alpha);
1101 return this->saveLayer(bounds, &tmpPaint);
1102 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001103}
1104
reed@android.com8a1c16f2008-12-17 15:59:43 +00001105void SkCanvas::internalRestore() {
1106 SkASSERT(fMCStack.count() != 0);
1107
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001108 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001109 DeviceCM* layer = fMCRec->fLayer; // may be null
1110 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001111 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001112
1113 // now do the normal restore()
1114 fMCRec->~MCRec(); // balanced in save()
1115 fMCStack.pop_back();
1116 fMCRec = (MCRec*)fMCStack.back();
1117
Mike Reedc42a1cd2017-02-14 14:25:14 -05001118 if (fMCRec) {
1119 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1120 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001121
reed@android.com8a1c16f2008-12-17 15:59:43 +00001122 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1123 since if we're being recorded, we don't want to record this (the
1124 recorder will have already recorded the restore).
1125 */
bsalomon49f085d2014-09-05 13:34:00 -07001126 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001127 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001128 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001129 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001130 layer->fPaint.get(),
1131 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001132 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001133 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001134 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001135 delete layer;
reedb679ca82015-04-07 04:40:48 -07001136 } else {
1137 // we're at the root
reeda499f902015-05-01 09:34:31 -07001138 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001139 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001140 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001142 }
msarettfbfa2582016-08-12 08:29:08 -07001143
1144 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001145 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001146 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1147 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001148}
1149
reede8f30622016-03-23 18:59:25 -07001150sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001151 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001152 props = &fProps;
1153 }
1154 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001155}
1156
reede8f30622016-03-23 18:59:25 -07001157sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001158 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001159 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001160}
1161
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001162SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001163 return this->onImageInfo();
1164}
1165
1166SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001167 SkBaseDevice* dev = this->getDevice();
1168 if (dev) {
1169 return dev->imageInfo();
1170 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001171 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001172 }
1173}
1174
brianosman898235c2016-04-06 07:38:23 -07001175bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001176 return this->onGetProps(props);
1177}
1178
1179bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001180 SkBaseDevice* dev = this->getDevice();
1181 if (dev) {
1182 if (props) {
1183 *props = fProps;
1184 }
1185 return true;
1186 } else {
1187 return false;
1188 }
1189}
1190
reed6ceeebd2016-03-09 14:26:26 -08001191bool SkCanvas::peekPixels(SkPixmap* pmap) {
1192 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001193}
1194
reed884e97c2015-05-26 11:31:54 -07001195bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001196 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001197 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001198}
1199
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001200void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001201 SkPixmap pmap;
1202 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001203 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001204 }
1205 if (info) {
1206 *info = pmap.info();
1207 }
1208 if (rowBytes) {
1209 *rowBytes = pmap.rowBytes();
1210 }
1211 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001212 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001213 }
reed884e97c2015-05-26 11:31:54 -07001214 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001215}
1216
reed884e97c2015-05-26 11:31:54 -07001217bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001218 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001219 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001220}
1221
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223
Florin Malita53f77bd2017-04-28 13:48:37 -04001224void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1225 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001227 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228 paint = &tmp;
1229 }
reed@google.com4b226022011-01-11 18:32:13 +00001230
Ben Wagner2c312c42018-06-27 14:46:46 -04001231 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001232
reed@android.com8a1c16f2008-12-17 15:59:43 +00001233 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001234 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001235 paint = &looper.paint();
1236 SkImageFilter* filter = paint->getImageFilter();
1237 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001238 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001239 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1240 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001241 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1242 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001243 }
reed@google.com76dd2772012-01-05 21:15:07 +00001244 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001245 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001246 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247 }
reeda2217ef2016-07-20 06:04:34 -07001248
reed@google.com4e2b3d32011-04-07 14:18:59 +00001249 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001250}
1251
reed32704672015-12-16 08:27:10 -08001252/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001253
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001254void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001255 if (dx || dy) {
1256 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001257 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001258
reedfe69b502016-09-12 06:31:48 -07001259 // Translate shouldn't affect the is-scale-translateness of the matrix.
1260 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001261
Mike Reedc42a1cd2017-02-14 14:25:14 -05001262 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001263
reedfe69b502016-09-12 06:31:48 -07001264 this->didTranslate(dx,dy);
1265 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266}
1267
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001268void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001269 SkMatrix m;
1270 m.setScale(sx, sy);
1271 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272}
1273
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001274void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001275 SkMatrix m;
1276 m.setRotate(degrees);
1277 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278}
1279
bungeman7438bfc2016-07-12 15:01:19 -07001280void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1281 SkMatrix m;
1282 m.setRotate(degrees, px, py);
1283 this->concat(m);
1284}
1285
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001286void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001287 SkMatrix m;
1288 m.setSkew(sx, sy);
1289 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001290}
1291
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001292void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001293 if (matrix.isIdentity()) {
1294 return;
1295 }
1296
reed2ff1fce2014-12-11 07:07:37 -08001297 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001298 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001299 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001300
Mike Reed7627fa52017-02-08 10:07:53 -05001301 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001302
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001303 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001304}
1305
reed8c30a812016-04-20 16:36:51 -07001306void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001307 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001308 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001309
Mike Reedc42a1cd2017-02-14 14:25:14 -05001310 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001311}
1312
1313void SkCanvas::setMatrix(const SkMatrix& matrix) {
1314 this->checkForDeferredSave();
1315 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001316 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317}
1318
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001320 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321}
1322
1323//////////////////////////////////////////////////////////////////////////////
1324
Mike Reedc1f77742016-12-09 09:00:50 -05001325void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001326 if (!rect.isFinite()) {
1327 return;
1328 }
reed2ff1fce2014-12-11 07:07:37 -08001329 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001330 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1331 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001332}
1333
Mike Reedc1f77742016-12-09 09:00:50 -05001334void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001335 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001336
Mike Reed7627fa52017-02-08 10:07:53 -05001337 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001338
reedc64eff52015-11-21 12:39:45 -08001339 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001340 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1341 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001342 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343}
1344
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001345void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1346 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001347 if (fClipRestrictionRect.isEmpty()) {
1348 // we notify the device, but we *dont* resolve deferred saves (since we're just
1349 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001350 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001351 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001352 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001353 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001354 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001355 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001356 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1357 }
1358}
1359
Mike Reedc1f77742016-12-09 09:00:50 -05001360void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001361 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001362 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001363 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001364 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1365 } else {
1366 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001367 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001368}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001369
Mike Reedc1f77742016-12-09 09:00:50 -05001370void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001371 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001372
Brian Salomona3b45d42016-10-03 11:36:16 -04001373 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001374
Mike Reed7627fa52017-02-08 10:07:53 -05001375 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001376
Mike Reed20800c82017-11-15 16:09:04 -05001377 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1378 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001379 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001380}
1381
Mike Reedc1f77742016-12-09 09:00:50 -05001382void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001383 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001384 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001385
1386 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1387 SkRect r;
1388 if (path.isRect(&r)) {
1389 this->onClipRect(r, op, edgeStyle);
1390 return;
1391 }
1392 SkRRect rrect;
1393 if (path.isOval(&r)) {
1394 rrect.setOval(r);
1395 this->onClipRRect(rrect, op, edgeStyle);
1396 return;
1397 }
1398 if (path.isRRect(&rrect)) {
1399 this->onClipRRect(rrect, op, edgeStyle);
1400 return;
1401 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001402 }
robertphillips39f05382015-11-24 09:30:12 -08001403
1404 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001405}
1406
Mike Reedc1f77742016-12-09 09:00:50 -05001407void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001408 AutoValidateClip avc(this);
1409
Brian Salomona3b45d42016-10-03 11:36:16 -04001410 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001411
Mike Reed7627fa52017-02-08 10:07:53 -05001412 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413
Brian Salomona3b45d42016-10-03 11:36:16 -04001414 const SkPath* rasterClipPath = &path;
1415 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001416 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1417 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001418 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001419}
1420
Mike Reedc1f77742016-12-09 09:00:50 -05001421void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001422 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001423 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001424}
1425
Mike Reedc1f77742016-12-09 09:00:50 -05001426void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001427 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001428
reed@google.com5c3d1472011-02-22 19:12:23 +00001429 AutoValidateClip avc(this);
1430
Mike Reed20800c82017-11-15 16:09:04 -05001431 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001432 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433}
1434
reed@google.com819c9212011-02-23 18:56:55 +00001435#ifdef SK_DEBUG
1436void SkCanvas::validateClip() const {
1437 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001438 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001439 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001440 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001441 return;
1442 }
reed@google.com819c9212011-02-23 18:56:55 +00001443}
1444#endif
1445
Mike Reeda1361362017-03-07 09:37:29 -05001446bool SkCanvas::androidFramework_isClipAA() const {
1447 bool containsAA = false;
1448
1449 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1450
1451 return containsAA;
1452}
1453
1454class RgnAccumulator {
1455 SkRegion* fRgn;
1456public:
1457 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1458 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1459 SkIPoint origin = device->getOrigin();
1460 if (origin.x() | origin.y()) {
1461 rgn->translate(origin.x(), origin.y());
1462 }
1463 fRgn->op(*rgn, SkRegion::kUnion_Op);
1464 }
1465};
1466
1467void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1468 RgnAccumulator accum(rgn);
1469 SkRegion tmp;
1470
1471 rgn->setEmpty();
1472 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001473}
1474
reed@google.com5c3d1472011-02-22 19:12:23 +00001475///////////////////////////////////////////////////////////////////////////////
1476
reed@google.com754de5f2014-02-24 19:38:20 +00001477bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001478 return fMCRec->fRasterClip.isEmpty();
1479
1480 // TODO: should we only use the conservative answer in a recording canvas?
1481#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001482 SkBaseDevice* dev = this->getTopDevice();
1483 // if no device we return true
1484 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001485#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001486}
1487
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001488bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001489 SkBaseDevice* dev = this->getTopDevice();
1490 // if no device we return false
1491 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001492}
1493
msarettfbfa2582016-08-12 08:29:08 -07001494static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1495#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1496 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1497 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1498 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1499 return 0xF != _mm_movemask_ps(mask);
1500#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1501 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1502 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1503 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1504 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1505#else
1506 SkRect devRectAsRect;
1507 SkRect devClipAsRect;
1508 devRect.store(&devRectAsRect.fLeft);
1509 devClip.store(&devClipAsRect.fLeft);
1510 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1511#endif
1512}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001513
msarettfbfa2582016-08-12 08:29:08 -07001514// It's important for this function to not be inlined. Otherwise the compiler will share code
1515// between the fast path and the slow path, resulting in two slow paths.
1516static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1517 const SkMatrix& matrix) {
1518 SkRect deviceRect;
1519 matrix.mapRect(&deviceRect, src);
1520 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1521}
1522
1523bool SkCanvas::quickReject(const SkRect& src) const {
1524#ifdef SK_DEBUG
1525 // Verify that fDeviceClipBounds are set properly.
1526 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001527 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001528 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001529 } else {
msarettfbfa2582016-08-12 08:29:08 -07001530 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001531 }
msarettfbfa2582016-08-12 08:29:08 -07001532
msarett9637ea92016-08-18 14:03:30 -07001533 // Verify that fIsScaleTranslate is set properly.
1534 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001535#endif
1536
msarett9637ea92016-08-18 14:03:30 -07001537 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001538 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1539 }
1540
1541 // We inline the implementation of mapScaleTranslate() for the fast path.
1542 float sx = fMCRec->fMatrix.getScaleX();
1543 float sy = fMCRec->fMatrix.getScaleY();
1544 float tx = fMCRec->fMatrix.getTranslateX();
1545 float ty = fMCRec->fMatrix.getTranslateY();
1546 Sk4f scale(sx, sy, sx, sy);
1547 Sk4f trans(tx, ty, tx, ty);
1548
1549 // Apply matrix.
1550 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1551
1552 // Make sure left < right, top < bottom.
1553 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1554 Sk4f min = Sk4f::Min(ltrb, rblt);
1555 Sk4f max = Sk4f::Max(ltrb, rblt);
1556 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1557 // ARM this sequence generates the fastest (a single instruction).
1558 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1559
1560 // Check if the device rect is NaN or outside the clip.
1561 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001562}
1563
reed@google.com3b3e8952012-08-16 20:53:31 +00001564bool SkCanvas::quickReject(const SkPath& path) const {
1565 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001566}
1567
Mike Klein83c8dd92017-11-28 17:08:45 -05001568SkRect SkCanvas::getLocalClipBounds() const {
1569 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001570 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001571 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001572 }
1573
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001574 SkMatrix inverse;
1575 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001576 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001577 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001578 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001579
Mike Reed42e8c532017-01-23 14:09:13 -05001580 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001581 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001582 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001583
Mike Reedb57b9312018-04-23 12:12:54 -04001584 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001585 inverse.mapRect(&bounds, r);
1586 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001587}
1588
Mike Klein83c8dd92017-11-28 17:08:45 -05001589SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001590 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001591}
1592
reed@android.com8a1c16f2008-12-17 15:59:43 +00001593const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001594 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001595}
1596
Brian Osman11052242016-10-27 14:47:55 -04001597GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001598 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001599 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001600}
1601
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001602GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001603 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001604 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001605}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001606
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001607void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1608 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001609 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001610 if (outer.isEmpty()) {
1611 return;
1612 }
1613 if (inner.isEmpty()) {
1614 this->drawRRect(outer, paint);
1615 return;
1616 }
1617
1618 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001619 // be able to return ...
1620 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001621 //
1622 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001623 if (!outer.getBounds().contains(inner.getBounds())) {
1624 return;
1625 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001626
1627 this->onDrawDRRect(outer, inner, paint);
1628}
1629
reed41af9662015-01-05 07:49:08 -08001630void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001631 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001632 this->onDrawPaint(paint);
1633}
1634
1635void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001636 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001637 // To avoid redundant logic in our culling code and various backends, we always sort rects
1638 // before passing them along.
1639 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001640}
1641
msarettdca352e2016-08-26 06:37:45 -07001642void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001643 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001644 if (region.isEmpty()) {
1645 return;
1646 }
1647
1648 if (region.isRect()) {
1649 return this->drawIRect(region.getBounds(), paint);
1650 }
1651
1652 this->onDrawRegion(region, paint);
1653}
1654
reed41af9662015-01-05 07:49:08 -08001655void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001656 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001657 // To avoid redundant logic in our culling code and various backends, we always sort rects
1658 // before passing them along.
1659 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001660}
1661
1662void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001663 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001664 this->onDrawRRect(rrect, paint);
1665}
1666
1667void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001668 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001669 this->onDrawPoints(mode, count, pts, paint);
1670}
1671
Mike Reede88a1cb2017-03-17 09:50:46 -04001672void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1673 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001674 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001675 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001676 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1677 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001678 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001679}
1680
1681void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001682 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001683 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001684 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1685}
1686
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001687void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1688 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001689 TRACE_EVENT0("skia", TRACE_FUNC);
1690 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001691 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001692 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1693}
1694
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001695void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1696 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001697 TRACE_EVENT0("skia", TRACE_FUNC);
1698 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001699 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001700 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001701}
1702
1703void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001704 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001705 this->onDrawPath(path, paint);
1706}
1707
reeda85d4d02015-05-06 12:56:48 -07001708void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001709 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001710 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001711 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001712}
1713
Mike Reedc4e31092018-01-30 11:15:27 -05001714// Returns true if the rect can be "filled" : non-empty and finite
1715static bool fillable(const SkRect& r) {
1716 SkScalar w = r.width();
1717 SkScalar h = r.height();
1718 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1719}
1720
reede47829b2015-08-06 10:02:53 -07001721void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1722 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001723 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001724 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001725 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001726 return;
1727 }
1728 this->onDrawImageRect(image, &src, dst, paint, constraint);
1729}
reed41af9662015-01-05 07:49:08 -08001730
reed84984ef2015-07-17 07:09:43 -07001731void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1732 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001733 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001734 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001735}
1736
reede47829b2015-08-06 10:02:53 -07001737void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1738 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001739 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001740 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1741 constraint);
1742}
reede47829b2015-08-06 10:02:53 -07001743
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001744namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001745class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001746public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001747 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1748 if (!origPaint) {
1749 return;
1750 }
1751 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1752 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1753 }
1754 if (origPaint->getMaskFilter()) {
1755 fPaint.writable()->setMaskFilter(nullptr);
1756 }
1757 if (origPaint->isAntiAlias()) {
1758 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001759 }
1760 }
1761
1762 const SkPaint* get() const {
1763 return fPaint;
1764 }
1765
1766private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001767 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001768};
1769} // namespace
1770
reed4c21dc52015-06-25 12:32:03 -07001771void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1772 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001773 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001774 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001775 if (dst.isEmpty()) {
1776 return;
1777 }
msarett552bca92016-08-03 06:53:26 -07001778 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001779 LatticePaint latticePaint(paint);
1780 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001781 } else {
reede47829b2015-08-06 10:02:53 -07001782 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001783 }
reed4c21dc52015-06-25 12:32:03 -07001784}
1785
msarett16882062016-08-16 09:31:08 -07001786void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1787 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001788 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001789 RETURN_ON_NULL(image);
1790 if (dst.isEmpty()) {
1791 return;
1792 }
msarett71df2d72016-09-30 12:41:42 -07001793
1794 SkIRect bounds;
1795 Lattice latticePlusBounds = lattice;
1796 if (!latticePlusBounds.fBounds) {
1797 bounds = SkIRect::MakeWH(image->width(), image->height());
1798 latticePlusBounds.fBounds = &bounds;
1799 }
1800
1801 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001802 LatticePaint latticePaint(paint);
1803 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001804 } else {
1805 this->drawImageRect(image, dst, paint);
1806 }
1807}
1808
reed41af9662015-01-05 07:49:08 -08001809void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001810 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001811 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001812 return;
1813 }
reed41af9662015-01-05 07:49:08 -08001814 this->onDrawBitmap(bitmap, dx, dy, paint);
1815}
1816
reede47829b2015-08-06 10:02:53 -07001817void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001818 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001819 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001820 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001821 return;
1822 }
reede47829b2015-08-06 10:02:53 -07001823 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001824}
1825
reed84984ef2015-07-17 07:09:43 -07001826void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1827 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001828 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001829}
1830
reede47829b2015-08-06 10:02:53 -07001831void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1832 SrcRectConstraint constraint) {
1833 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1834 constraint);
1835}
reede47829b2015-08-06 10:02:53 -07001836
reed41af9662015-01-05 07:49:08 -08001837void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1838 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001839 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001840 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001841 return;
1842 }
msarett552bca92016-08-03 06:53:26 -07001843 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001844 LatticePaint latticePaint(paint);
1845 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001846 } else {
reeda5517e22015-07-14 10:54:12 -07001847 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001848 }
reed41af9662015-01-05 07:49:08 -08001849}
1850
msarettc573a402016-08-02 08:05:56 -07001851void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1852 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001853 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001854 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001855 return;
1856 }
msarett71df2d72016-09-30 12:41:42 -07001857
1858 SkIRect bounds;
1859 Lattice latticePlusBounds = lattice;
1860 if (!latticePlusBounds.fBounds) {
1861 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1862 latticePlusBounds.fBounds = &bounds;
1863 }
1864
1865 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001866 LatticePaint latticePaint(paint);
1867 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001868 } else {
msarett16882062016-08-16 09:31:08 -07001869 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001870 }
msarettc573a402016-08-02 08:05:56 -07001871}
1872
reed71c3c762015-06-24 10:29:17 -07001873void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001874 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001875 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001876 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001877 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001878 if (count <= 0) {
1879 return;
1880 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001881 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001882 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001883 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001884}
1885
reedf70b5312016-03-04 16:36:20 -08001886void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001887 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001888 if (key) {
1889 this->onDrawAnnotation(rect, key, value);
1890 }
1891}
1892
reede47829b2015-08-06 10:02:53 -07001893void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1894 const SkPaint* paint, SrcRectConstraint constraint) {
1895 if (src) {
1896 this->drawImageRect(image, *src, dst, paint, constraint);
1897 } else {
1898 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1899 dst, paint, constraint);
1900 }
1901}
1902void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1903 const SkPaint* paint, SrcRectConstraint constraint) {
1904 if (src) {
1905 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1906 } else {
1907 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1908 dst, paint, constraint);
1909 }
1910}
1911
Mike Reed4204da22017-05-17 08:53:36 -04001912void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001913 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001914 this->onDrawShadowRec(path, rec);
1915}
1916
1917void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1918 SkPaint paint;
1919 const SkRect& pathBounds = path.getBounds();
1920
Ben Wagner2c312c42018-06-27 14:46:46 -04001921 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001922 while (iter.next()) {
1923 iter.fDevice->drawShadow(path, rec);
1924 }
1925 LOOPER_END
1926}
1927
reed@android.com8a1c16f2008-12-17 15:59:43 +00001928//////////////////////////////////////////////////////////////////////////////
1929// These are the virtual drawing methods
1930//////////////////////////////////////////////////////////////////////////////
1931
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001932void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001933 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001934 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1935 }
1936}
1937
reed41af9662015-01-05 07:49:08 -08001938void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001939 this->internalDrawPaint(paint);
1940}
1941
1942void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04001943 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001944
1945 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001946 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001947 }
1948
reed@google.com4e2b3d32011-04-07 14:18:59 +00001949 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001950}
1951
reed41af9662015-01-05 07:49:08 -08001952void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1953 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001954 if ((long)count <= 0) {
1955 return;
1956 }
1957
Mike Reed822128b2017-02-28 16:41:03 -05001958 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001959 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001960 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001961 // special-case 2 points (common for drawing a single line)
1962 if (2 == count) {
1963 r.set(pts[0], pts[1]);
1964 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001965 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001966 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001967 if (!r.isFinite()) {
1968 return;
1969 }
Mike Reed822128b2017-02-28 16:41:03 -05001970 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001971 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1972 return;
1973 }
1974 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001975 }
reed@google.coma584aed2012-05-16 14:06:02 +00001976
halcanary96fcdcc2015-08-27 07:41:13 -07001977 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001978
Ben Wagner2c312c42018-06-27 14:46:46 -04001979 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001980
reed@android.com8a1c16f2008-12-17 15:59:43 +00001981 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001982 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001983 }
reed@google.com4b226022011-01-11 18:32:13 +00001984
reed@google.com4e2b3d32011-04-07 14:18:59 +00001985 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001986}
1987
reed4a167172016-08-18 17:15:25 -07001988static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1989 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07001990 (intptr_t)paint.getLooper() ) != 0;
1991}
1992
reed41af9662015-01-05 07:49:08 -08001993void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001994 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001995 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001996 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001997 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001998 return;
1999 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002000 }
reed@google.com4b226022011-01-11 18:32:13 +00002001
reed4a167172016-08-18 17:15:25 -07002002 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002003 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002004
reed4a167172016-08-18 17:15:25 -07002005 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002006 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002007 }
2008
2009 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002010 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002011 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002012 SkDrawIter iter(this);
2013 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002014 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002015 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002016 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002017}
2018
msarett44df6512016-08-25 13:54:30 -07002019void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002020 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002021 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002022 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002023 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2024 return;
2025 }
msarett44df6512016-08-25 13:54:30 -07002026 }
2027
Ben Wagner2c312c42018-06-27 14:46:46 -04002028 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002029
2030 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002031 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002032 }
2033
2034 LOOPER_END
2035}
2036
reed41af9662015-01-05 07:49:08 -08002037void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002038 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002039 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002040 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002041 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002042 return;
2043 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002044 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002045
Ben Wagner2c312c42018-06-27 14:46:46 -04002046 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002047
2048 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002049 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002050 }
2051
2052 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002053}
2054
bsalomonac3aa242016-08-19 11:25:19 -07002055void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2056 SkScalar sweepAngle, bool useCenter,
2057 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002058 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002059 if (paint.canComputeFastBounds()) {
2060 SkRect storage;
2061 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002062 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002063 return;
2064 }
bsalomonac3aa242016-08-19 11:25:19 -07002065 }
2066
Ben Wagner2c312c42018-06-27 14:46:46 -04002067 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002068
2069 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002070 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002071 }
2072
2073 LOOPER_END
2074}
2075
reed41af9662015-01-05 07:49:08 -08002076void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002077 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002078 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002079 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2080 return;
2081 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002082 }
2083
2084 if (rrect.isRect()) {
2085 // call the non-virtual version
2086 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002087 return;
2088 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002089 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002090 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2091 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002092 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002093
Ben Wagner2c312c42018-06-27 14:46:46 -04002094 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002095
2096 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002097 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002098 }
2099
2100 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002101}
2102
Mike Reed822128b2017-02-28 16:41:03 -05002103void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002104 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002105 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002106 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2107 return;
2108 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002109 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002110
Ben Wagner2c312c42018-06-27 14:46:46 -04002111 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002112
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002113 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002114 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002115 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002116
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002117 LOOPER_END
2118}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002119
reed41af9662015-01-05 07:49:08 -08002120void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002121 if (!path.isFinite()) {
2122 return;
2123 }
2124
Mike Reed822128b2017-02-28 16:41:03 -05002125 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002126 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002127 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002128 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2129 return;
2130 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002131 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002132
Mike Reed822128b2017-02-28 16:41:03 -05002133 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002134 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002135 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002136 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002137 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002138 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002139
Ben Wagner2c312c42018-06-27 14:46:46 -04002140 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002141
2142 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002143 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002144 }
2145
reed@google.com4e2b3d32011-04-07 14:18:59 +00002146 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002147}
2148
reed262a71b2015-12-05 13:07:27 -08002149bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002150 if (!paint.getImageFilter()) {
2151 return false;
2152 }
2153
2154 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002155 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002156 return false;
2157 }
2158
2159 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2160 // Once we can filter and the filter will return a result larger than itself, we should be
2161 // able to remove this constraint.
2162 // skbug.com/4526
2163 //
2164 SkPoint pt;
2165 ctm.mapXY(x, y, &pt);
2166 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2167 return ir.contains(fMCRec->fRasterClip.getBounds());
2168}
2169
Mike Reedf441cfc2018-04-11 14:50:16 -04002170// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2171// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2172// null.
2173static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2174 if (paintParam) {
2175 *real = *paintParam;
2176 real->setStyle(SkPaint::kFill_Style);
2177 real->setPathEffect(nullptr);
2178 paintParam = real;
2179 }
2180 return paintParam;
2181}
2182
reeda85d4d02015-05-06 12:56:48 -07002183void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002184 SkPaint realPaint;
2185 paint = init_image_paint(&realPaint, paint);
2186
reeda85d4d02015-05-06 12:56:48 -07002187 SkRect bounds = SkRect::MakeXYWH(x, y,
2188 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002189 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002190 SkRect tmp = bounds;
2191 if (paint) {
2192 paint->computeFastBounds(tmp, &tmp);
2193 }
2194 if (this->quickReject(tmp)) {
2195 return;
2196 }
reeda85d4d02015-05-06 12:56:48 -07002197 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002198 // At this point we need a real paint object. If the caller passed null, then we should
2199 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2200 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2201 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002202
reeda2217ef2016-07-20 06:04:34 -07002203 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002204 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2205 *paint);
2206 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002207 special = this->getDevice()->makeSpecial(image);
2208 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002209 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002210 }
2211 }
2212
reed262a71b2015-12-05 13:07:27 -08002213 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2214
reeda85d4d02015-05-06 12:56:48 -07002215 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002216 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002217 if (special) {
2218 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002219 iter.fDevice->ctm().mapXY(x, y, &pt);
2220 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002221 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002222 SkScalarRoundToInt(pt.fY), pnt,
2223 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002224 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002225 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002226 }
reeda85d4d02015-05-06 12:56:48 -07002227 }
halcanary9d524f22016-03-29 09:03:52 -07002228
reeda85d4d02015-05-06 12:56:48 -07002229 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002230}
2231
reed41af9662015-01-05 07:49:08 -08002232void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002233 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002234 SkPaint realPaint;
2235 paint = init_image_paint(&realPaint, paint);
2236
halcanary96fcdcc2015-08-27 07:41:13 -07002237 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002238 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002239 if (paint) {
2240 paint->computeFastBounds(dst, &storage);
2241 }
2242 if (this->quickReject(storage)) {
2243 return;
2244 }
reeda85d4d02015-05-06 12:56:48 -07002245 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002246 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002247
Ben Wagner2c312c42018-06-27 14:46:46 -04002248 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002249
reeda85d4d02015-05-06 12:56:48 -07002250 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002251 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002252 }
halcanary9d524f22016-03-29 09:03:52 -07002253
reeda85d4d02015-05-06 12:56:48 -07002254 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002255}
2256
reed41af9662015-01-05 07:49:08 -08002257void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002258 SkDEBUGCODE(bitmap.validate();)
2259
reed33366972015-10-08 09:22:02 -07002260 if (bitmap.drawsNothing()) {
2261 return;
2262 }
2263
Mike Reedf441cfc2018-04-11 14:50:16 -04002264 SkPaint realPaint;
2265 init_image_paint(&realPaint, paint);
2266 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002267
Mike Reed822128b2017-02-28 16:41:03 -05002268 SkRect bounds;
2269 bitmap.getBounds(&bounds);
2270 bounds.offset(x, y);
2271 bool canFastBounds = paint->canComputeFastBounds();
2272 if (canFastBounds) {
2273 SkRect storage;
2274 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002275 return;
2276 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002277 }
reed@google.com4b226022011-01-11 18:32:13 +00002278
reeda2217ef2016-07-20 06:04:34 -07002279 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002280 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2281 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002282 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002283 special = this->getDevice()->makeSpecial(bitmap);
2284 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002285 drawAsSprite = false;
2286 }
2287 }
2288
Mike Reed822128b2017-02-28 16:41:03 -05002289 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002290
2291 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002292 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002293 if (special) {
reed262a71b2015-12-05 13:07:27 -08002294 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002295 iter.fDevice->ctm().mapXY(x, y, &pt);
2296 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002297 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002298 SkScalarRoundToInt(pt.fY), pnt,
2299 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002300 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002301 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002302 }
reed33366972015-10-08 09:22:02 -07002303 }
msarettfbfa2582016-08-12 08:29:08 -07002304
reed33366972015-10-08 09:22:02 -07002305 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002306}
2307
reed@google.com9987ec32011-09-07 11:57:52 +00002308// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002309void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002310 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002311 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002312 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002313 return;
2314 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002315
halcanary96fcdcc2015-08-27 07:41:13 -07002316 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002317 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002318 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2319 return;
2320 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002321 }
reed@google.com3d608122011-11-21 15:16:16 +00002322
reed@google.com33535f32012-09-25 15:37:50 +00002323 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002324 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002325 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002326 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002327
Ben Wagner2c312c42018-06-27 14:46:46 -04002328 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002329
reed@google.com33535f32012-09-25 15:37:50 +00002330 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002331 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002332 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002333
reed@google.com33535f32012-09-25 15:37:50 +00002334 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002335}
2336
reed41af9662015-01-05 07:49:08 -08002337void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002338 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002339 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002340 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002341}
2342
reed4c21dc52015-06-25 12:32:03 -07002343void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2344 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002345 SkPaint realPaint;
2346 paint = init_image_paint(&realPaint, paint);
2347
halcanary96fcdcc2015-08-27 07:41:13 -07002348 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002349 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002350 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2351 return;
2352 }
reed@google.com3d608122011-11-21 15:16:16 +00002353 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002354 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002355
Ben Wagner2c312c42018-06-27 14:46:46 -04002356 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002357
reed4c21dc52015-06-25 12:32:03 -07002358 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002359 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002360 }
halcanary9d524f22016-03-29 09:03:52 -07002361
reed4c21dc52015-06-25 12:32:03 -07002362 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002363}
2364
reed41af9662015-01-05 07:49:08 -08002365void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2366 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002367 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002368 SkPaint realPaint;
2369 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002370
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 }
reed4c21dc52015-06-25 12:32:03 -07002376 }
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->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002383 }
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
msarett16882062016-08-16 09:31:08 -07002388void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2389 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002390 SkPaint realPaint;
2391 paint = init_image_paint(&realPaint, paint);
2392
msarett16882062016-08-16 09:31:08 -07002393 if (nullptr == paint || paint->canComputeFastBounds()) {
2394 SkRect storage;
2395 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2396 return;
2397 }
2398 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002399 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002400
Ben Wagner2c312c42018-06-27 14:46:46 -04002401 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002402
2403 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002404 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002405 }
2406
2407 LOOPER_END
2408}
2409
2410void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2411 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002412 SkPaint realPaint;
2413 paint = init_image_paint(&realPaint, paint);
2414
msarett16882062016-08-16 09:31:08 -07002415 if (nullptr == paint || paint->canComputeFastBounds()) {
2416 SkRect storage;
2417 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2418 return;
2419 }
2420 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002421 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002422
Ben Wagner2c312c42018-06-27 14:46:46 -04002423 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002424
2425 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002426 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002427 }
2428
2429 LOOPER_END
2430}
2431
reed@google.come0d9ce82014-04-23 04:00:17 +00002432void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2433 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002434
Ben Wagner2c312c42018-06-27 14:46:46 -04002435 LOOPER_BEGIN(paint, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002436
2437 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002438 fScratchGlyphRunBuilder->drawText(
Herb Derby4a447432018-06-22 11:45:27 -04002439 looper.paint(), text, byteLength, SkPoint::Make(x, y));
Herb Derby8a6348e2018-07-12 15:30:35 -04002440 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002441 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002442 }
2443
reed@google.com4e2b3d32011-04-07 14:18:59 +00002444 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002445}
2446
reed@google.come0d9ce82014-04-23 04:00:17 +00002447void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2448 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002449
Ben Wagner2c312c42018-06-27 14:46:46 -04002450 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002451
reed@android.com8a1c16f2008-12-17 15:59:43 +00002452 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002453 fScratchGlyphRunBuilder->drawPosText(looper.paint(), text, byteLength, pos);
Herb Derby8a6348e2018-07-12 15:30:35 -04002454 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002455 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002456 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002457
reed@google.com4e2b3d32011-04-07 14:18:59 +00002458 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002459}
2460
reed@google.come0d9ce82014-04-23 04:00:17 +00002461void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2462 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002463
Ben Wagner2c312c42018-06-27 14:46:46 -04002464 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002465
reed@android.com8a1c16f2008-12-17 15:59:43 +00002466 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002467 fScratchGlyphRunBuilder->drawPosTextH(
Herb Derby4a447432018-06-22 11:45:27 -04002468 looper.paint(), text, byteLength, xpos, constY);
Herb Derby8a6348e2018-07-12 15:30:35 -04002469 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002470 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002471 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002472
reed@google.com4e2b3d32011-04-07 14:18:59 +00002473 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474}
2475
reed@google.come0d9ce82014-04-23 04:00:17 +00002476void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2477 const SkMatrix* matrix, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002478 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002479
reed@android.com8a1c16f2008-12-17 15:59:43 +00002480 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002481 iter.fDevice->drawTextOnPath(text, byteLength, path, matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002483
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002484 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002485}
2486
Herb Derby2eacff02018-07-18 13:41:15 -04002487void SkCanvas::onDrawTextRSXform(const void* text, size_t len, const SkRSXform xform[],
reed45561a02016-07-07 12:47:17 -07002488 const SkRect* cullRect, const SkPaint& paint) {
2489 if (cullRect && this->quickReject(*cullRect)) {
2490 return;
2491 }
2492
Ben Wagner2c312c42018-06-27 14:46:46 -04002493 LOOPER_BEGIN(paint, nullptr)
reed45561a02016-07-07 12:47:17 -07002494
2495 while (iter.next()) {
Herb Derby2eacff02018-07-18 13:41:15 -04002496 fScratchGlyphRunBuilder->drawTextAtOrigin(paint, text, len);
2497 auto list = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb935cf82018-07-26 16:54:18 -04002498 if (!list.empty()) {
2499 auto glyphRun = list[0];
Herb Derby2eacff02018-07-18 13:41:15 -04002500 iter.fDevice->drawGlyphRunRSXform(&glyphRun, xform);
2501 }
reed45561a02016-07-07 12:47:17 -07002502 }
2503
2504 LOOPER_END
2505}
2506
fmalita00d5c2c2014-08-21 08:53:26 -07002507void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2508 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002509 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002510 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002511 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002512 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002513 SkRect tmp;
2514 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2515 return;
2516 }
2517 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002518 }
2519
fmalita024f9962015-03-03 19:08:17 -08002520 // We cannot filter in the looper as we normally do, because the paint is
2521 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002522 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002523
fmalitaaa1b9122014-08-28 14:32:24 -07002524 while (iter.next()) {
Herb Derbyb983e6b2018-07-13 13:26:29 -04002525 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, SkPoint::Make(x, y));
2526 iter.fDevice->drawGlyphRunList(fScratchGlyphRunBuilder->useGlyphRunList());
fmalita00d5c2c2014-08-21 08:53:26 -07002527 }
2528
fmalitaaa1b9122014-08-28 14:32:24 -07002529 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002530}
2531
Cary Clark2a475ea2017-04-28 15:35:12 -04002532void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2533 this->drawText(string.c_str(), string.size(), x, y, paint);
2534}
2535
reed@google.come0d9ce82014-04-23 04:00:17 +00002536// These will become non-virtual, so they always call the (virtual) onDraw... method
2537void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2538 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002539 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002540 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002541 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002542 this->onDrawText(text, byteLength, x, y, paint);
2543 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002544}
2545void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2546 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002547 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002548 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002549 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002550 this->onDrawPosText(text, byteLength, pos, paint);
2551 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002552}
2553void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2554 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002555 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002556 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002557 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002558 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2559 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002560}
2561void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2562 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002563 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002564 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002565 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002566 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2567 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002568}
reed45561a02016-07-07 12:47:17 -07002569void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2570 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002571 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002572 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002573 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002574 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2575 }
2576}
fmalita00d5c2c2014-08-21 08:53:26 -07002577void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2578 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002579 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002580 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002581 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002582 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002583}
reed@google.come0d9ce82014-04-23 04:00:17 +00002584
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002585void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002586 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002587 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002588
2589 while (iter.next()) {
2590 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002591 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002592 }
2593
2594 LOOPER_END
2595}
2596
dandovb3c9d1c2014-08-12 08:34:29 -07002597void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002598 const SkPoint texCoords[4], SkBlendMode bmode,
2599 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002600 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002601 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002602 return;
2603 }
mtklein6cfa73a2014-08-13 13:33:49 -07002604
Mike Reedfaba3712016-11-03 14:45:31 -04002605 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002606}
2607
2608void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002609 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002610 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002611 // Since a patch is always within the convex hull of the control points, we discard it when its
2612 // bounding rectangle is completely outside the current clip.
2613 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002614 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002615 if (this->quickReject(bounds)) {
2616 return;
2617 }
mtklein6cfa73a2014-08-13 13:33:49 -07002618
Ben Wagner2c312c42018-06-27 14:46:46 -04002619 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002620
dandovecfff212014-08-04 10:02:00 -07002621 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002622 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002623 }
mtklein6cfa73a2014-08-13 13:33:49 -07002624
dandovecfff212014-08-04 10:02:00 -07002625 LOOPER_END
2626}
2627
reeda8db7282015-07-07 10:22:31 -07002628void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002629#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002630 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002631#endif
reede3b38ce2016-01-08 09:18:44 -08002632 RETURN_ON_NULL(dr);
2633 if (x || y) {
2634 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2635 this->onDrawDrawable(dr, &matrix);
2636 } else {
2637 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002638 }
2639}
2640
reeda8db7282015-07-07 10:22:31 -07002641void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002642#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002643 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002644#endif
reede3b38ce2016-01-08 09:18:44 -08002645 RETURN_ON_NULL(dr);
2646 if (matrix && matrix->isIdentity()) {
2647 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002648 }
reede3b38ce2016-01-08 09:18:44 -08002649 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002650}
2651
2652void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002653 // drawable bounds are no longer reliable (e.g. android displaylist)
2654 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002655 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002656}
2657
reed71c3c762015-06-24 10:29:17 -07002658void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002659 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002660 const SkRect* cull, const SkPaint* paint) {
2661 if (cull && this->quickReject(*cull)) {
2662 return;
2663 }
2664
2665 SkPaint pnt;
2666 if (paint) {
2667 pnt = *paint;
2668 }
halcanary9d524f22016-03-29 09:03:52 -07002669
Ben Wagner2c312c42018-06-27 14:46:46 -04002670 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002671 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002672 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002673 }
2674 LOOPER_END
2675}
2676
reedf70b5312016-03-04 16:36:20 -08002677void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2678 SkASSERT(key);
2679
2680 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002681 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002682 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002683 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002684 }
2685 LOOPER_END
2686}
2687
reed@android.com8a1c16f2008-12-17 15:59:43 +00002688//////////////////////////////////////////////////////////////////////////////
2689// These methods are NOT virtual, and therefore must call back into virtual
2690// methods, rather than actually drawing themselves.
2691//////////////////////////////////////////////////////////////////////////////
2692
reed374772b2016-10-05 17:33:02 -07002693void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002694 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002695 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002696 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697 this->drawPaint(paint);
2698}
2699
2700void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002701 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002702 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2703}
2704
Mike Reed3661bc92017-02-22 13:21:42 -05002705void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002706 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002707 pts[0].set(x0, y0);
2708 pts[1].set(x1, y1);
2709 this->drawPoints(kLines_PointMode, 2, pts, paint);
2710}
2711
Mike Reed3661bc92017-02-22 13:21:42 -05002712void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002713 if (radius < 0) {
2714 radius = 0;
2715 }
2716
2717 SkRect r;
2718 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002719 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002720}
2721
2722void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2723 const SkPaint& paint) {
2724 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002725 SkRRect rrect;
2726 rrect.setRectXY(r, rx, ry);
2727 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002728 } else {
2729 this->drawRect(r, paint);
2730 }
2731}
2732
reed@android.com8a1c16f2008-12-17 15:59:43 +00002733void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2734 SkScalar sweepAngle, bool useCenter,
2735 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002736 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002737 if (oval.isEmpty() || !sweepAngle) {
2738 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002739 }
bsalomon21af9ca2016-08-25 12:29:23 -07002740 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002741}
2742
2743void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2744 const SkPath& path, SkScalar hOffset,
2745 SkScalar vOffset, const SkPaint& paint) {
2746 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002747
reed@android.com8a1c16f2008-12-17 15:59:43 +00002748 matrix.setTranslate(hOffset, vOffset);
2749 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2750}
2751
reed@android.comf76bacf2009-05-13 14:00:33 +00002752///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002753
Mike Klein88d90712018-01-27 17:30:04 +00002754/**
2755 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2756 * against the playback cost of recursing into the subpicture to get at its actual ops.
2757 *
2758 * For now we pick a conservatively small value, though measurement (and other heuristics like
2759 * the type of ops contained) may justify changing this value.
2760 */
2761#define kMaxPictureOpsToUnrollInsteadOfRef 1
2762
reedd5fa1a42014-08-09 11:08:05 -07002763void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002764 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002765 RETURN_ON_NULL(picture);
2766
reede3b38ce2016-01-08 09:18:44 -08002767 if (matrix && matrix->isIdentity()) {
2768 matrix = nullptr;
2769 }
Mike Klein88d90712018-01-27 17:30:04 +00002770 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2771 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2772 picture->playback(this);
2773 } else {
2774 this->onDrawPicture(picture, matrix, paint);
2775 }
reedd5fa1a42014-08-09 11:08:05 -07002776}
robertphillips9b14f262014-06-04 05:40:44 -07002777
reedd5fa1a42014-08-09 11:08:05 -07002778void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2779 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002780 if (!paint || paint->canComputeFastBounds()) {
2781 SkRect bounds = picture->cullRect();
2782 if (paint) {
2783 paint->computeFastBounds(bounds, &bounds);
2784 }
2785 if (matrix) {
2786 matrix->mapRect(&bounds);
2787 }
2788 if (this->quickReject(bounds)) {
2789 return;
2790 }
2791 }
2792
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002793 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002794 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795}
2796
reed@android.com8a1c16f2008-12-17 15:59:43 +00002797///////////////////////////////////////////////////////////////////////////////
2798///////////////////////////////////////////////////////////////////////////////
2799
reed3aafe112016-08-18 12:45:34 -07002800SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002801 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002802
2803 SkASSERT(canvas);
2804
reed3aafe112016-08-18 12:45:34 -07002805 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002806 fDone = !fImpl->next();
2807}
2808
2809SkCanvas::LayerIter::~LayerIter() {
2810 fImpl->~SkDrawIter();
2811}
2812
2813void SkCanvas::LayerIter::next() {
2814 fDone = !fImpl->next();
2815}
2816
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002817SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002818 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002819}
2820
2821const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002822 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823}
2824
2825const SkPaint& SkCanvas::LayerIter::paint() const {
2826 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002827 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002828 paint = &fDefaultPaint;
2829 }
2830 return *paint;
2831}
2832
Mike Reedca37f322018-03-08 13:22:16 -05002833SkIRect SkCanvas::LayerIter::clipBounds() const {
2834 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002835}
2836
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2838int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002839
2840///////////////////////////////////////////////////////////////////////////////
2841
Brian Osman10fc6fd2018-03-02 11:01:10 -05002842// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002843static bool supported_for_raster_canvas(const SkImageInfo& info) {
2844 switch (info.alphaType()) {
2845 case kPremul_SkAlphaType:
2846 case kOpaque_SkAlphaType:
2847 break;
2848 default:
2849 return false;
2850 }
2851
2852 switch (info.colorType()) {
2853 case kAlpha_8_SkColorType:
2854 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002855 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002856 case kRGBA_F16_SkColorType:
Mike Klein37854712018-06-26 11:43:06 -04002857 case kRGBA_F32_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002858 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002859 break;
2860 default:
2861 return false;
2862 }
2863
2864 return true;
2865}
2866
Mike Reed5df49342016-11-12 08:06:55 -06002867std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002868 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002869 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002870 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002871 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002872
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002873 SkBitmap bitmap;
2874 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002875 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002876 }
Mike Reed12f77342017-11-08 11:19:52 -05002877
2878 return props ?
2879 skstd::make_unique<SkCanvas>(bitmap, *props) :
2880 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002881}
reedd5fa1a42014-08-09 11:08:05 -07002882
2883///////////////////////////////////////////////////////////////////////////////
2884
Florin Malitaee424ac2016-12-01 12:47:59 -05002885SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2886 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2887
Florin Malita439ace92016-12-02 12:05:41 -05002888SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2889 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2890
Herb Derbyefe39bc2018-05-01 17:06:20 -04002891SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002892 : INHERITED(device) {}
2893
Florin Malitaee424ac2016-12-01 12:47:59 -05002894SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2895 (void)this->INHERITED::getSaveLayerStrategy(rec);
2896 return kNoLayer_SaveLayerStrategy;
2897}
2898
2899///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002900
reed73603f32016-09-20 08:42:38 -07002901static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2902static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2903static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2904static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2905static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2906static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002907
2908///////////////////////////////////////////////////////////////////////////////////////////////////
2909
2910SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2911 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002912 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002913 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2914 SkIPoint origin = dev->getOrigin();
2915 SkMatrix ctm = this->getTotalMatrix();
2916 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2917
2918 SkIRect clip = fMCRec->fRasterClip.getBounds();
2919 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002920 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002921 clip.setEmpty();
2922 }
2923
2924 fAllocator->updateHandle(handle, ctm, clip);
2925 return handle;
2926 }
2927 return nullptr;
2928}
2929
2930static bool install(SkBitmap* bm, const SkImageInfo& info,
2931 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002932 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002933}
2934
2935SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2936 SkBitmap* bm) {
2937 SkRasterHandleAllocator::Rec rec;
2938 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2939 return nullptr;
2940 }
2941 return rec.fHandle;
2942}
2943
2944std::unique_ptr<SkCanvas>
2945SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2946 const SkImageInfo& info, const Rec* rec) {
2947 if (!alloc || !supported_for_raster_canvas(info)) {
2948 return nullptr;
2949 }
2950
2951 SkBitmap bm;
2952 Handle hndl;
2953
2954 if (rec) {
2955 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2956 } else {
2957 hndl = alloc->allocBitmap(info, &bm);
2958 }
2959 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2960}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002961
2962///////////////////////////////////////////////////////////////////////////////////////////////////
2963
2964