blob: cb98b09b37097a20b83e11ca331c4188760e43fb [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) {
923 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
reed4960eee2015-12-18 07:09:18 -0800924 fSaveCount += 1;
Cary Clarke041e312018-03-06 13:00:52 -0500925 this->internalSaveLayer(rec, strategy);
reed4960eee2015-12-18 07:09:18 -0800926 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800927}
928
reeda2217ef2016-07-20 06:04:34 -0700929void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500930 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500931 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700932 SkDraw draw;
933 SkRasterClip rc;
934 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
935 if (!dst->accessPixels(&draw.fDst)) {
936 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800937 }
reeda2217ef2016-07-20 06:04:34 -0700938 draw.fMatrix = &SkMatrix::I();
939 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800940
941 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500942 if (filter) {
943 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
944 }
reeda2217ef2016-07-20 06:04:34 -0700945
Mike Reedc42a1cd2017-02-14 14:25:14 -0500946 int x = src->getOrigin().x() - dstOrigin.x();
947 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700948 auto special = src->snapSpecial();
949 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400950 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700951 }
robertphillips7354a4b2015-12-16 05:08:27 -0800952}
reed70ee31b2015-12-10 13:44:45 -0800953
Mike Kleine083f7c2018-02-07 12:54:27 -0500954static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500955 // Need to force L32 for now if we have an image filter.
956 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
957 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500958 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800959 }
Mike Klein649fb732018-02-26 15:09:16 -0500960
961 SkColorType ct = prev.colorType();
962 if (prev.bytesPerPixel() <= 4) {
963 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
964 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
965 ct = kN32_SkColorType;
966 }
967 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800968}
969
reed4960eee2015-12-18 07:09:18 -0800970void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
971 const SkRect* bounds = rec.fBounds;
972 const SkPaint* paint = rec.fPaint;
973 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
974
reed8c30a812016-04-20 16:36:51 -0700975 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400976 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700977 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400978 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700979 SkMatrix remainder;
980 SkSize scale;
981 /*
982 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
983 * but they do handle scaling. To accommodate this, we do the following:
984 *
985 * 1. Stash off the current CTM
986 * 2. Decompose the CTM into SCALE and REMAINDER
987 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
988 * contains the REMAINDER
989 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
990 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
991 * of the original imagefilter, and draw that (via drawSprite)
992 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
993 *
994 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
995 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
996 */
reed96a04f32016-04-25 09:25:15 -0700997 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -0700998 stashedMatrix.decomposeScale(&scale, &remainder))
999 {
1000 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -04001001 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -07001002 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1003 SkPaint* p = lazyP.set(*paint);
1004 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1005 SkFilterQuality::kLow_SkFilterQuality,
1006 sk_ref_sp(imageFilter)));
1007 imageFilter = p->getImageFilter();
1008 paint = p;
1009 }
reed8c30a812016-04-20 16:36:51 -07001010
junov@chromium.orga907ac32012-02-24 21:54:07 +00001011 // do this before we create the layer. We don't call the public save() since
1012 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001013 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001014
junov@chromium.orga907ac32012-02-24 21:54:07 +00001015 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001016 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001017 if (modifiedRec) {
1018 // In this case there will be no layer in which to stash the matrix so we need to
1019 // revert the prior MCRec to its earlier state.
1020 modifiedRec->fMatrix = stashedMatrix;
1021 }
reed2ff1fce2014-12-11 07:07:37 -08001022 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023 }
1024
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001025 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1026 // the clipRectBounds() call above?
1027 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001028 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001029 }
1030
reed8dc0ccb2015-03-20 06:32:52 -07001031 SkPixelGeometry geo = fProps.pixelGeometry();
1032 if (paint) {
reed76033be2015-03-14 10:54:31 -07001033 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001034 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001035 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001036 }
1037 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001038
robertphillips5139e502016-07-19 05:10:40 -07001039 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001040 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001041 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001042 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001043 }
reedb2db8982014-11-13 12:41:02 -08001044
Mike Kleine083f7c2018-02-07 12:54:27 -05001045 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001046
Hal Canary704cd322016-11-07 14:13:52 -05001047 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001048 {
reed70ee31b2015-12-10 13:44:45 -08001049 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001050 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001051 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001052 const bool trackCoverage =
1053 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001054 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001055 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001056 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001057 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001058 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1059 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001060 return;
reed61f501f2015-04-29 08:34:00 -07001061 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001062 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001063 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064
Mike Reedb43a3e02017-02-11 10:18:58 -05001065 // only have a "next" if this new layer doesn't affect the clip (rare)
1066 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067 fMCRec->fLayer = layer;
1068 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001069
Mike Reedc61abee2017-02-28 17:45:27 -05001070 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001071 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001072 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001073 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001074
Mike Reedc42a1cd2017-02-14 14:25:14 -05001075 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1076
1077 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1078 if (layer->fNext) {
1079 // need to punch a hole in the previous device, so we don't draw there, given that
1080 // the new top-layer will allow drawing to happen "below" it.
1081 SkRegion hole(ir);
1082 do {
1083 layer = layer->fNext;
1084 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1085 } while (layer->fNext);
1086 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087}
1088
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001089int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001090 if (0xFF == alpha) {
1091 return this->saveLayer(bounds, nullptr);
1092 } else {
1093 SkPaint tmpPaint;
1094 tmpPaint.setAlpha(alpha);
1095 return this->saveLayer(bounds, &tmpPaint);
1096 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001097}
1098
reed@android.com8a1c16f2008-12-17 15:59:43 +00001099void SkCanvas::internalRestore() {
1100 SkASSERT(fMCStack.count() != 0);
1101
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001102 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001103 DeviceCM* layer = fMCRec->fLayer; // may be null
1104 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001105 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106
1107 // now do the normal restore()
1108 fMCRec->~MCRec(); // balanced in save()
1109 fMCStack.pop_back();
1110 fMCRec = (MCRec*)fMCStack.back();
1111
Mike Reedc42a1cd2017-02-14 14:25:14 -05001112 if (fMCRec) {
1113 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1114 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001115
reed@android.com8a1c16f2008-12-17 15:59:43 +00001116 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1117 since if we're being recorded, we don't want to record this (the
1118 recorder will have already recorded the restore).
1119 */
bsalomon49f085d2014-09-05 13:34:00 -07001120 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001121 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001122 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001123 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001124 layer->fPaint.get(),
1125 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001126 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001127 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001128 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001129 delete layer;
reedb679ca82015-04-07 04:40:48 -07001130 } else {
1131 // we're at the root
reeda499f902015-05-01 09:34:31 -07001132 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001133 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001134 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001135 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001136 }
msarettfbfa2582016-08-12 08:29:08 -07001137
1138 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001139 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001140 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1141 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001142}
1143
reede8f30622016-03-23 18:59:25 -07001144sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001145 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001146 props = &fProps;
1147 }
1148 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001149}
1150
reede8f30622016-03-23 18:59:25 -07001151sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001152 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001153 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001154}
1155
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001156SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001157 return this->onImageInfo();
1158}
1159
1160SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001161 SkBaseDevice* dev = this->getDevice();
1162 if (dev) {
1163 return dev->imageInfo();
1164 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001165 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001166 }
1167}
1168
brianosman898235c2016-04-06 07:38:23 -07001169bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001170 return this->onGetProps(props);
1171}
1172
1173bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001174 SkBaseDevice* dev = this->getDevice();
1175 if (dev) {
1176 if (props) {
1177 *props = fProps;
1178 }
1179 return true;
1180 } else {
1181 return false;
1182 }
1183}
1184
reed6ceeebd2016-03-09 14:26:26 -08001185bool SkCanvas::peekPixels(SkPixmap* pmap) {
1186 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001187}
1188
reed884e97c2015-05-26 11:31:54 -07001189bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001190 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001191 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001192}
1193
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001194void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001195 SkPixmap pmap;
1196 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001197 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001198 }
1199 if (info) {
1200 *info = pmap.info();
1201 }
1202 if (rowBytes) {
1203 *rowBytes = pmap.rowBytes();
1204 }
1205 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001206 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001207 }
reed884e97c2015-05-26 11:31:54 -07001208 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001209}
1210
reed884e97c2015-05-26 11:31:54 -07001211bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001212 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001213 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001214}
1215
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217
Florin Malita53f77bd2017-04-28 13:48:37 -04001218void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1219 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001220 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001221 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222 paint = &tmp;
1223 }
reed@google.com4b226022011-01-11 18:32:13 +00001224
Ben Wagner2c312c42018-06-27 14:46:46 -04001225 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001226
reed@android.com8a1c16f2008-12-17 15:59:43 +00001227 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001228 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001229 paint = &looper.paint();
1230 SkImageFilter* filter = paint->getImageFilter();
1231 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001232 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001233 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1234 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001235 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1236 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001237 }
reed@google.com76dd2772012-01-05 21:15:07 +00001238 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001239 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001240 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241 }
reeda2217ef2016-07-20 06:04:34 -07001242
reed@google.com4e2b3d32011-04-07 14:18:59 +00001243 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244}
1245
reed32704672015-12-16 08:27:10 -08001246/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001247
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001248void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001249 if (dx || dy) {
1250 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001251 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001252
reedfe69b502016-09-12 06:31:48 -07001253 // Translate shouldn't affect the is-scale-translateness of the matrix.
1254 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001255
Mike Reedc42a1cd2017-02-14 14:25:14 -05001256 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001257
reedfe69b502016-09-12 06:31:48 -07001258 this->didTranslate(dx,dy);
1259 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260}
1261
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001262void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001263 SkMatrix m;
1264 m.setScale(sx, sy);
1265 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266}
1267
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001268void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001269 SkMatrix m;
1270 m.setRotate(degrees);
1271 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272}
1273
bungeman7438bfc2016-07-12 15:01:19 -07001274void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1275 SkMatrix m;
1276 m.setRotate(degrees, px, py);
1277 this->concat(m);
1278}
1279
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001280void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001281 SkMatrix m;
1282 m.setSkew(sx, sy);
1283 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001284}
1285
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001286void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001287 if (matrix.isIdentity()) {
1288 return;
1289 }
1290
reed2ff1fce2014-12-11 07:07:37 -08001291 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001292 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001293 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001294
Mike Reed7627fa52017-02-08 10:07:53 -05001295 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001296
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001297 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001298}
1299
reed8c30a812016-04-20 16:36:51 -07001300void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001301 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001302 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001303
Mike Reedc42a1cd2017-02-14 14:25:14 -05001304 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001305}
1306
1307void SkCanvas::setMatrix(const SkMatrix& matrix) {
1308 this->checkForDeferredSave();
1309 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001310 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311}
1312
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001314 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315}
1316
1317//////////////////////////////////////////////////////////////////////////////
1318
Mike Reedc1f77742016-12-09 09:00:50 -05001319void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001320 if (!rect.isFinite()) {
1321 return;
1322 }
reed2ff1fce2014-12-11 07:07:37 -08001323 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001324 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1325 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001326}
1327
Mike Reedc1f77742016-12-09 09:00:50 -05001328void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001329 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001330
Mike Reed7627fa52017-02-08 10:07:53 -05001331 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001332
reedc64eff52015-11-21 12:39:45 -08001333 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001334 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1335 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001336 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337}
1338
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001339void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1340 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001341 if (fClipRestrictionRect.isEmpty()) {
1342 // we notify the device, but we *dont* resolve deferred saves (since we're just
1343 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001344 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001345 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001346 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001347 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001348 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001349 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001350 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1351 }
1352}
1353
Mike Reedc1f77742016-12-09 09:00:50 -05001354void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001355 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001356 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001357 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001358 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1359 } else {
1360 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001361 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001362}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001363
Mike Reedc1f77742016-12-09 09:00:50 -05001364void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001365 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001366
Brian Salomona3b45d42016-10-03 11:36:16 -04001367 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001368
Mike Reed7627fa52017-02-08 10:07:53 -05001369 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001370
Mike Reed20800c82017-11-15 16:09:04 -05001371 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1372 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001373 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001374}
1375
Mike Reedc1f77742016-12-09 09:00:50 -05001376void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001377 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001378 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001379
1380 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1381 SkRect r;
1382 if (path.isRect(&r)) {
1383 this->onClipRect(r, op, edgeStyle);
1384 return;
1385 }
1386 SkRRect rrect;
1387 if (path.isOval(&r)) {
1388 rrect.setOval(r);
1389 this->onClipRRect(rrect, op, edgeStyle);
1390 return;
1391 }
1392 if (path.isRRect(&rrect)) {
1393 this->onClipRRect(rrect, op, edgeStyle);
1394 return;
1395 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001396 }
robertphillips39f05382015-11-24 09:30:12 -08001397
1398 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001399}
1400
Mike Reedc1f77742016-12-09 09:00:50 -05001401void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001402 AutoValidateClip avc(this);
1403
Brian Salomona3b45d42016-10-03 11:36:16 -04001404 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001405
Mike Reed7627fa52017-02-08 10:07:53 -05001406 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407
Brian Salomona3b45d42016-10-03 11:36:16 -04001408 const SkPath* rasterClipPath = &path;
1409 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001410 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1411 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001412 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413}
1414
Mike Reedc1f77742016-12-09 09:00:50 -05001415void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001416 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001417 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001418}
1419
Mike Reedc1f77742016-12-09 09:00:50 -05001420void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001421 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001422
reed@google.com5c3d1472011-02-22 19:12:23 +00001423 AutoValidateClip avc(this);
1424
Mike Reed20800c82017-11-15 16:09:04 -05001425 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001426 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001427}
1428
reed@google.com819c9212011-02-23 18:56:55 +00001429#ifdef SK_DEBUG
1430void SkCanvas::validateClip() const {
1431 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001432 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001433 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001434 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001435 return;
1436 }
reed@google.com819c9212011-02-23 18:56:55 +00001437}
1438#endif
1439
Mike Reeda1361362017-03-07 09:37:29 -05001440bool SkCanvas::androidFramework_isClipAA() const {
1441 bool containsAA = false;
1442
1443 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1444
1445 return containsAA;
1446}
1447
1448class RgnAccumulator {
1449 SkRegion* fRgn;
1450public:
1451 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1452 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1453 SkIPoint origin = device->getOrigin();
1454 if (origin.x() | origin.y()) {
1455 rgn->translate(origin.x(), origin.y());
1456 }
1457 fRgn->op(*rgn, SkRegion::kUnion_Op);
1458 }
1459};
1460
1461void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1462 RgnAccumulator accum(rgn);
1463 SkRegion tmp;
1464
1465 rgn->setEmpty();
1466 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001467}
1468
reed@google.com5c3d1472011-02-22 19:12:23 +00001469///////////////////////////////////////////////////////////////////////////////
1470
reed@google.com754de5f2014-02-24 19:38:20 +00001471bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001472 return fMCRec->fRasterClip.isEmpty();
1473
1474 // TODO: should we only use the conservative answer in a recording canvas?
1475#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001476 SkBaseDevice* dev = this->getTopDevice();
1477 // if no device we return true
1478 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001479#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001480}
1481
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001482bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001483 SkBaseDevice* dev = this->getTopDevice();
1484 // if no device we return false
1485 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001486}
1487
msarettfbfa2582016-08-12 08:29:08 -07001488static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1489#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1490 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1491 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1492 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1493 return 0xF != _mm_movemask_ps(mask);
1494#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1495 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1496 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1497 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1498 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1499#else
1500 SkRect devRectAsRect;
1501 SkRect devClipAsRect;
1502 devRect.store(&devRectAsRect.fLeft);
1503 devClip.store(&devClipAsRect.fLeft);
1504 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1505#endif
1506}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001507
msarettfbfa2582016-08-12 08:29:08 -07001508// It's important for this function to not be inlined. Otherwise the compiler will share code
1509// between the fast path and the slow path, resulting in two slow paths.
1510static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1511 const SkMatrix& matrix) {
1512 SkRect deviceRect;
1513 matrix.mapRect(&deviceRect, src);
1514 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1515}
1516
1517bool SkCanvas::quickReject(const SkRect& src) const {
1518#ifdef SK_DEBUG
1519 // Verify that fDeviceClipBounds are set properly.
1520 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001521 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001522 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001523 } else {
msarettfbfa2582016-08-12 08:29:08 -07001524 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001525 }
msarettfbfa2582016-08-12 08:29:08 -07001526
msarett9637ea92016-08-18 14:03:30 -07001527 // Verify that fIsScaleTranslate is set properly.
1528 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001529#endif
1530
msarett9637ea92016-08-18 14:03:30 -07001531 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001532 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1533 }
1534
1535 // We inline the implementation of mapScaleTranslate() for the fast path.
1536 float sx = fMCRec->fMatrix.getScaleX();
1537 float sy = fMCRec->fMatrix.getScaleY();
1538 float tx = fMCRec->fMatrix.getTranslateX();
1539 float ty = fMCRec->fMatrix.getTranslateY();
1540 Sk4f scale(sx, sy, sx, sy);
1541 Sk4f trans(tx, ty, tx, ty);
1542
1543 // Apply matrix.
1544 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1545
1546 // Make sure left < right, top < bottom.
1547 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1548 Sk4f min = Sk4f::Min(ltrb, rblt);
1549 Sk4f max = Sk4f::Max(ltrb, rblt);
1550 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1551 // ARM this sequence generates the fastest (a single instruction).
1552 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1553
1554 // Check if the device rect is NaN or outside the clip.
1555 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001556}
1557
reed@google.com3b3e8952012-08-16 20:53:31 +00001558bool SkCanvas::quickReject(const SkPath& path) const {
1559 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001560}
1561
Mike Klein83c8dd92017-11-28 17:08:45 -05001562SkRect SkCanvas::getLocalClipBounds() const {
1563 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001564 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001565 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001566 }
1567
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001568 SkMatrix inverse;
1569 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001570 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001571 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001572 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001573
Mike Reed42e8c532017-01-23 14:09:13 -05001574 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001575 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001576 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001577
Mike Reedb57b9312018-04-23 12:12:54 -04001578 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001579 inverse.mapRect(&bounds, r);
1580 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001581}
1582
Mike Klein83c8dd92017-11-28 17:08:45 -05001583SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001584 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001585}
1586
reed@android.com8a1c16f2008-12-17 15:59:43 +00001587const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001588 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001589}
1590
Brian Osman11052242016-10-27 14:47:55 -04001591GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001592 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001593 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001594}
1595
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001596GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001597 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001598 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001599}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001600
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001601void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1602 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001603 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001604 if (outer.isEmpty()) {
1605 return;
1606 }
1607 if (inner.isEmpty()) {
1608 this->drawRRect(outer, paint);
1609 return;
1610 }
1611
1612 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001613 // be able to return ...
1614 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001615 //
1616 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001617 if (!outer.getBounds().contains(inner.getBounds())) {
1618 return;
1619 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001620
1621 this->onDrawDRRect(outer, inner, paint);
1622}
1623
reed41af9662015-01-05 07:49:08 -08001624void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001625 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001626 this->onDrawPaint(paint);
1627}
1628
1629void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001630 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001631 // To avoid redundant logic in our culling code and various backends, we always sort rects
1632 // before passing them along.
1633 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001634}
1635
msarettdca352e2016-08-26 06:37:45 -07001636void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001637 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001638 if (region.isEmpty()) {
1639 return;
1640 }
1641
1642 if (region.isRect()) {
1643 return this->drawIRect(region.getBounds(), paint);
1644 }
1645
1646 this->onDrawRegion(region, paint);
1647}
1648
reed41af9662015-01-05 07:49:08 -08001649void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001650 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001651 // To avoid redundant logic in our culling code and various backends, we always sort rects
1652 // before passing them along.
1653 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001654}
1655
1656void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001657 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001658 this->onDrawRRect(rrect, paint);
1659}
1660
1661void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001662 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001663 this->onDrawPoints(mode, count, pts, paint);
1664}
1665
Mike Reede88a1cb2017-03-17 09:50:46 -04001666void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1667 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001668 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001669 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001670 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1671 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001672 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001673}
1674
1675void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001676 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001677 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001678 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1679}
1680
Ruiqi Mao94d57c42018-07-02 15:20:10 -04001681void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkMatrix* bones, int boneCount,
Ruiqi Maof5101492018-06-29 14:32:21 -04001682 SkBlendMode mode, const SkPaint& paint) {
1683 TRACE_EVENT0("skia", TRACE_FUNC);
1684 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001685 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001686 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1687}
1688
1689void SkCanvas::drawVertices(const SkVertices* vertices, const SkMatrix* bones, int boneCount,
1690 SkBlendMode mode, const SkPaint& paint) {
1691 TRACE_EVENT0("skia", TRACE_FUNC);
1692 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001693 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001694 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001695}
1696
1697void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001698 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001699 this->onDrawPath(path, paint);
1700}
1701
reeda85d4d02015-05-06 12:56:48 -07001702void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001703 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001704 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001705 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001706}
1707
Mike Reedc4e31092018-01-30 11:15:27 -05001708// Returns true if the rect can be "filled" : non-empty and finite
1709static bool fillable(const SkRect& r) {
1710 SkScalar w = r.width();
1711 SkScalar h = r.height();
1712 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1713}
1714
reede47829b2015-08-06 10:02:53 -07001715void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1716 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001717 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001718 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001719 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001720 return;
1721 }
1722 this->onDrawImageRect(image, &src, dst, paint, constraint);
1723}
reed41af9662015-01-05 07:49:08 -08001724
reed84984ef2015-07-17 07:09:43 -07001725void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1726 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001727 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001728 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001729}
1730
reede47829b2015-08-06 10:02:53 -07001731void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1732 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001733 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001734 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1735 constraint);
1736}
reede47829b2015-08-06 10:02:53 -07001737
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001738namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001739class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001740public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001741 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1742 if (!origPaint) {
1743 return;
1744 }
1745 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1746 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1747 }
1748 if (origPaint->getMaskFilter()) {
1749 fPaint.writable()->setMaskFilter(nullptr);
1750 }
1751 if (origPaint->isAntiAlias()) {
1752 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001753 }
1754 }
1755
1756 const SkPaint* get() const {
1757 return fPaint;
1758 }
1759
1760private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001761 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001762};
1763} // namespace
1764
reed4c21dc52015-06-25 12:32:03 -07001765void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1766 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001767 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001768 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001769 if (dst.isEmpty()) {
1770 return;
1771 }
msarett552bca92016-08-03 06:53:26 -07001772 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001773 LatticePaint latticePaint(paint);
1774 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001775 } else {
reede47829b2015-08-06 10:02:53 -07001776 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001777 }
reed4c21dc52015-06-25 12:32:03 -07001778}
1779
msarett16882062016-08-16 09:31:08 -07001780void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1781 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001782 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001783 RETURN_ON_NULL(image);
1784 if (dst.isEmpty()) {
1785 return;
1786 }
msarett71df2d72016-09-30 12:41:42 -07001787
1788 SkIRect bounds;
1789 Lattice latticePlusBounds = lattice;
1790 if (!latticePlusBounds.fBounds) {
1791 bounds = SkIRect::MakeWH(image->width(), image->height());
1792 latticePlusBounds.fBounds = &bounds;
1793 }
1794
1795 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001796 LatticePaint latticePaint(paint);
1797 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001798 } else {
1799 this->drawImageRect(image, dst, paint);
1800 }
1801}
1802
reed41af9662015-01-05 07:49:08 -08001803void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001804 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001805 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001806 return;
1807 }
reed41af9662015-01-05 07:49:08 -08001808 this->onDrawBitmap(bitmap, dx, dy, paint);
1809}
1810
reede47829b2015-08-06 10:02:53 -07001811void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001812 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001813 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001814 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001815 return;
1816 }
reede47829b2015-08-06 10:02:53 -07001817 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001818}
1819
reed84984ef2015-07-17 07:09:43 -07001820void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1821 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001822 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001823}
1824
reede47829b2015-08-06 10:02:53 -07001825void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1826 SrcRectConstraint constraint) {
1827 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1828 constraint);
1829}
reede47829b2015-08-06 10:02:53 -07001830
reed41af9662015-01-05 07:49:08 -08001831void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1832 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001833 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001834 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001835 return;
1836 }
msarett552bca92016-08-03 06:53:26 -07001837 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001838 LatticePaint latticePaint(paint);
1839 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001840 } else {
reeda5517e22015-07-14 10:54:12 -07001841 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001842 }
reed41af9662015-01-05 07:49:08 -08001843}
1844
msarettc573a402016-08-02 08:05:56 -07001845void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1846 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001847 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001848 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001849 return;
1850 }
msarett71df2d72016-09-30 12:41:42 -07001851
1852 SkIRect bounds;
1853 Lattice latticePlusBounds = lattice;
1854 if (!latticePlusBounds.fBounds) {
1855 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1856 latticePlusBounds.fBounds = &bounds;
1857 }
1858
1859 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001860 LatticePaint latticePaint(paint);
1861 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001862 } else {
msarett16882062016-08-16 09:31:08 -07001863 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001864 }
msarettc573a402016-08-02 08:05:56 -07001865}
1866
reed71c3c762015-06-24 10:29:17 -07001867void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001868 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001869 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001870 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001871 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001872 if (count <= 0) {
1873 return;
1874 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001875 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001876 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001877 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001878}
1879
reedf70b5312016-03-04 16:36:20 -08001880void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001881 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001882 if (key) {
1883 this->onDrawAnnotation(rect, key, value);
1884 }
1885}
1886
reede47829b2015-08-06 10:02:53 -07001887void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1888 const SkPaint* paint, SrcRectConstraint constraint) {
1889 if (src) {
1890 this->drawImageRect(image, *src, dst, paint, constraint);
1891 } else {
1892 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1893 dst, paint, constraint);
1894 }
1895}
1896void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1897 const SkPaint* paint, SrcRectConstraint constraint) {
1898 if (src) {
1899 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1900 } else {
1901 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1902 dst, paint, constraint);
1903 }
1904}
1905
Mike Reed4204da22017-05-17 08:53:36 -04001906void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001907 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001908 this->onDrawShadowRec(path, rec);
1909}
1910
1911void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1912 SkPaint paint;
1913 const SkRect& pathBounds = path.getBounds();
1914
Ben Wagner2c312c42018-06-27 14:46:46 -04001915 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001916 while (iter.next()) {
1917 iter.fDevice->drawShadow(path, rec);
1918 }
1919 LOOPER_END
1920}
1921
reed@android.com8a1c16f2008-12-17 15:59:43 +00001922//////////////////////////////////////////////////////////////////////////////
1923// These are the virtual drawing methods
1924//////////////////////////////////////////////////////////////////////////////
1925
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001926void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001927 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001928 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1929 }
1930}
1931
reed41af9662015-01-05 07:49:08 -08001932void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001933 this->internalDrawPaint(paint);
1934}
1935
1936void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04001937 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001938
1939 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001940 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001941 }
1942
reed@google.com4e2b3d32011-04-07 14:18:59 +00001943 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001944}
1945
reed41af9662015-01-05 07:49:08 -08001946void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1947 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001948 if ((long)count <= 0) {
1949 return;
1950 }
1951
Mike Reed822128b2017-02-28 16:41:03 -05001952 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001953 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001954 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001955 // special-case 2 points (common for drawing a single line)
1956 if (2 == count) {
1957 r.set(pts[0], pts[1]);
1958 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001959 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001960 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001961 if (!r.isFinite()) {
1962 return;
1963 }
Mike Reed822128b2017-02-28 16:41:03 -05001964 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001965 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1966 return;
1967 }
1968 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001969 }
reed@google.coma584aed2012-05-16 14:06:02 +00001970
halcanary96fcdcc2015-08-27 07:41:13 -07001971 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001972
Ben Wagner2c312c42018-06-27 14:46:46 -04001973 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001974
reed@android.com8a1c16f2008-12-17 15:59:43 +00001975 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001976 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001977 }
reed@google.com4b226022011-01-11 18:32:13 +00001978
reed@google.com4e2b3d32011-04-07 14:18:59 +00001979 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001980}
1981
reed4a167172016-08-18 17:15:25 -07001982static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1983 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07001984 (intptr_t)paint.getLooper() ) != 0;
1985}
1986
reed41af9662015-01-05 07:49:08 -08001987void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001988 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001989 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001990 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001991 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001992 return;
1993 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001994 }
reed@google.com4b226022011-01-11 18:32:13 +00001995
reed4a167172016-08-18 17:15:25 -07001996 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04001997 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001998
reed4a167172016-08-18 17:15:25 -07001999 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002000 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002001 }
2002
2003 LOOPER_END
2004 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002005 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002006 SkDrawIter iter(this);
2007 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002008 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002009 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002010 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002011}
2012
msarett44df6512016-08-25 13:54:30 -07002013void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002014 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002015 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002016 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002017 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2018 return;
2019 }
msarett44df6512016-08-25 13:54:30 -07002020 }
2021
Ben Wagner2c312c42018-06-27 14:46:46 -04002022 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002023
2024 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002025 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002026 }
2027
2028 LOOPER_END
2029}
2030
reed41af9662015-01-05 07:49:08 -08002031void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002032 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002033 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002034 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002035 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002036 return;
2037 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002038 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002039
Ben Wagner2c312c42018-06-27 14:46:46 -04002040 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002041
2042 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002043 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002044 }
2045
2046 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002047}
2048
bsalomonac3aa242016-08-19 11:25:19 -07002049void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2050 SkScalar sweepAngle, bool useCenter,
2051 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002052 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002053 if (paint.canComputeFastBounds()) {
2054 SkRect storage;
2055 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002056 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002057 return;
2058 }
bsalomonac3aa242016-08-19 11:25:19 -07002059 }
2060
Ben Wagner2c312c42018-06-27 14:46:46 -04002061 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002062
2063 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002064 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002065 }
2066
2067 LOOPER_END
2068}
2069
reed41af9662015-01-05 07:49:08 -08002070void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002071 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002072 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002073 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2074 return;
2075 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002076 }
2077
2078 if (rrect.isRect()) {
2079 // call the non-virtual version
2080 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002081 return;
2082 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002083 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002084 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2085 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002086 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002087
Ben Wagner2c312c42018-06-27 14:46:46 -04002088 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002089
2090 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002091 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002092 }
2093
2094 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002095}
2096
Mike Reed822128b2017-02-28 16:41:03 -05002097void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002098 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002099 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002100 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2101 return;
2102 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002103 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002104
Ben Wagner2c312c42018-06-27 14:46:46 -04002105 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002106
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002107 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002108 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002109 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002110
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002111 LOOPER_END
2112}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002113
reed41af9662015-01-05 07:49:08 -08002114void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002115 if (!path.isFinite()) {
2116 return;
2117 }
2118
Mike Reed822128b2017-02-28 16:41:03 -05002119 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002120 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002121 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002122 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2123 return;
2124 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002125 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002126
Mike Reed822128b2017-02-28 16:41:03 -05002127 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002128 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002129 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002130 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002131 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002132 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002133
Ben Wagner2c312c42018-06-27 14:46:46 -04002134 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002135
2136 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002137 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002138 }
2139
reed@google.com4e2b3d32011-04-07 14:18:59 +00002140 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002141}
2142
reed262a71b2015-12-05 13:07:27 -08002143bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002144 if (!paint.getImageFilter()) {
2145 return false;
2146 }
2147
2148 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002149 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002150 return false;
2151 }
2152
2153 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2154 // Once we can filter and the filter will return a result larger than itself, we should be
2155 // able to remove this constraint.
2156 // skbug.com/4526
2157 //
2158 SkPoint pt;
2159 ctm.mapXY(x, y, &pt);
2160 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2161 return ir.contains(fMCRec->fRasterClip.getBounds());
2162}
2163
Mike Reedf441cfc2018-04-11 14:50:16 -04002164// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2165// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2166// null.
2167static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2168 if (paintParam) {
2169 *real = *paintParam;
2170 real->setStyle(SkPaint::kFill_Style);
2171 real->setPathEffect(nullptr);
2172 paintParam = real;
2173 }
2174 return paintParam;
2175}
2176
reeda85d4d02015-05-06 12:56:48 -07002177void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002178 SkPaint realPaint;
2179 paint = init_image_paint(&realPaint, paint);
2180
reeda85d4d02015-05-06 12:56:48 -07002181 SkRect bounds = SkRect::MakeXYWH(x, y,
2182 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002183 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002184 SkRect tmp = bounds;
2185 if (paint) {
2186 paint->computeFastBounds(tmp, &tmp);
2187 }
2188 if (this->quickReject(tmp)) {
2189 return;
2190 }
reeda85d4d02015-05-06 12:56:48 -07002191 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002192 // At this point we need a real paint object. If the caller passed null, then we should
2193 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2194 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2195 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002196
reeda2217ef2016-07-20 06:04:34 -07002197 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002198 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2199 *paint);
2200 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002201 special = this->getDevice()->makeSpecial(image);
2202 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002203 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002204 }
2205 }
2206
reed262a71b2015-12-05 13:07:27 -08002207 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2208
reeda85d4d02015-05-06 12:56:48 -07002209 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002210 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002211 if (special) {
2212 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002213 iter.fDevice->ctm().mapXY(x, y, &pt);
2214 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002215 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002216 SkScalarRoundToInt(pt.fY), pnt,
2217 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002218 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002219 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002220 }
reeda85d4d02015-05-06 12:56:48 -07002221 }
halcanary9d524f22016-03-29 09:03:52 -07002222
reeda85d4d02015-05-06 12:56:48 -07002223 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002224}
2225
reed41af9662015-01-05 07:49:08 -08002226void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002227 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002228 SkPaint realPaint;
2229 paint = init_image_paint(&realPaint, paint);
2230
halcanary96fcdcc2015-08-27 07:41:13 -07002231 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002232 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002233 if (paint) {
2234 paint->computeFastBounds(dst, &storage);
2235 }
2236 if (this->quickReject(storage)) {
2237 return;
2238 }
reeda85d4d02015-05-06 12:56:48 -07002239 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002240 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002241
Ben Wagner2c312c42018-06-27 14:46:46 -04002242 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002243
reeda85d4d02015-05-06 12:56:48 -07002244 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002245 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002246 }
halcanary9d524f22016-03-29 09:03:52 -07002247
reeda85d4d02015-05-06 12:56:48 -07002248 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002249}
2250
reed41af9662015-01-05 07:49:08 -08002251void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002252 SkDEBUGCODE(bitmap.validate();)
2253
reed33366972015-10-08 09:22:02 -07002254 if (bitmap.drawsNothing()) {
2255 return;
2256 }
2257
Mike Reedf441cfc2018-04-11 14:50:16 -04002258 SkPaint realPaint;
2259 init_image_paint(&realPaint, paint);
2260 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002261
Mike Reed822128b2017-02-28 16:41:03 -05002262 SkRect bounds;
2263 bitmap.getBounds(&bounds);
2264 bounds.offset(x, y);
2265 bool canFastBounds = paint->canComputeFastBounds();
2266 if (canFastBounds) {
2267 SkRect storage;
2268 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002269 return;
2270 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002271 }
reed@google.com4b226022011-01-11 18:32:13 +00002272
reeda2217ef2016-07-20 06:04:34 -07002273 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002274 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2275 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002276 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002277 special = this->getDevice()->makeSpecial(bitmap);
2278 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002279 drawAsSprite = false;
2280 }
2281 }
2282
Mike Reed822128b2017-02-28 16:41:03 -05002283 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002284
2285 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002286 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002287 if (special) {
reed262a71b2015-12-05 13:07:27 -08002288 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002289 iter.fDevice->ctm().mapXY(x, y, &pt);
2290 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002291 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002292 SkScalarRoundToInt(pt.fY), pnt,
2293 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002294 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002295 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002296 }
reed33366972015-10-08 09:22:02 -07002297 }
msarettfbfa2582016-08-12 08:29:08 -07002298
reed33366972015-10-08 09:22:02 -07002299 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002300}
2301
reed@google.com9987ec32011-09-07 11:57:52 +00002302// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002303void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002304 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002305 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002306 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307 return;
2308 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002309
halcanary96fcdcc2015-08-27 07:41:13 -07002310 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002311 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002312 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2313 return;
2314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002315 }
reed@google.com3d608122011-11-21 15:16:16 +00002316
reed@google.com33535f32012-09-25 15:37:50 +00002317 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002318 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002319 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002320 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002321
Ben Wagner2c312c42018-06-27 14:46:46 -04002322 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002323
reed@google.com33535f32012-09-25 15:37:50 +00002324 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002325 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002326 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002327
reed@google.com33535f32012-09-25 15:37:50 +00002328 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002329}
2330
reed41af9662015-01-05 07:49:08 -08002331void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002332 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002333 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002334 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002335}
2336
reed4c21dc52015-06-25 12:32:03 -07002337void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2338 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002339 SkPaint realPaint;
2340 paint = init_image_paint(&realPaint, paint);
2341
halcanary96fcdcc2015-08-27 07:41:13 -07002342 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002343 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002344 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2345 return;
2346 }
reed@google.com3d608122011-11-21 15:16:16 +00002347 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002348 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002349
Ben Wagner2c312c42018-06-27 14:46:46 -04002350 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002351
reed4c21dc52015-06-25 12:32:03 -07002352 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002353 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002354 }
halcanary9d524f22016-03-29 09:03:52 -07002355
reed4c21dc52015-06-25 12:32:03 -07002356 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002357}
2358
reed41af9662015-01-05 07:49:08 -08002359void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2360 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002361 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002362 SkPaint realPaint;
2363 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002364
halcanary96fcdcc2015-08-27 07:41:13 -07002365 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002366 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002367 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2368 return;
2369 }
reed4c21dc52015-06-25 12:32:03 -07002370 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002371 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002372
Ben Wagner2c312c42018-06-27 14:46:46 -04002373 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002374
reed4c21dc52015-06-25 12:32:03 -07002375 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002376 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002377 }
halcanary9d524f22016-03-29 09:03:52 -07002378
reed4c21dc52015-06-25 12:32:03 -07002379 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002380}
2381
msarett16882062016-08-16 09:31:08 -07002382void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2383 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002384 SkPaint realPaint;
2385 paint = init_image_paint(&realPaint, paint);
2386
msarett16882062016-08-16 09:31:08 -07002387 if (nullptr == paint || paint->canComputeFastBounds()) {
2388 SkRect storage;
2389 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2390 return;
2391 }
2392 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002393 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002394
Ben Wagner2c312c42018-06-27 14:46:46 -04002395 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002396
2397 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002398 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002399 }
2400
2401 LOOPER_END
2402}
2403
2404void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2405 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002406 SkPaint realPaint;
2407 paint = init_image_paint(&realPaint, paint);
2408
msarett16882062016-08-16 09:31:08 -07002409 if (nullptr == paint || paint->canComputeFastBounds()) {
2410 SkRect storage;
2411 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2412 return;
2413 }
2414 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002415 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002416
Ben Wagner2c312c42018-06-27 14:46:46 -04002417 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002418
2419 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002420 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002421 }
2422
2423 LOOPER_END
2424}
2425
reed@google.come0d9ce82014-04-23 04:00:17 +00002426void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2427 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002428
Ben Wagner2c312c42018-06-27 14:46:46 -04002429 LOOPER_BEGIN(paint, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002430
2431 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002432 fScratchGlyphRunBuilder->drawText(
Herb Derby4a447432018-06-22 11:45:27 -04002433 looper.paint(), text, byteLength, SkPoint::Make(x, y));
Herb Derby8a6348e2018-07-12 15:30:35 -04002434 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002435 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002436 }
2437
reed@google.com4e2b3d32011-04-07 14:18:59 +00002438 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002439}
2440
reed@google.come0d9ce82014-04-23 04:00:17 +00002441void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2442 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002443
Ben Wagner2c312c42018-06-27 14:46:46 -04002444 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002445
reed@android.com8a1c16f2008-12-17 15:59:43 +00002446 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002447 fScratchGlyphRunBuilder->drawPosText(looper.paint(), text, byteLength, pos);
Herb Derby8a6348e2018-07-12 15:30:35 -04002448 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002449 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002450 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002451
reed@google.com4e2b3d32011-04-07 14:18:59 +00002452 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002453}
2454
reed@google.come0d9ce82014-04-23 04:00:17 +00002455void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2456 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002457
Ben Wagner2c312c42018-06-27 14:46:46 -04002458 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002459
reed@android.com8a1c16f2008-12-17 15:59:43 +00002460 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002461 fScratchGlyphRunBuilder->drawPosTextH(
Herb Derby4a447432018-06-22 11:45:27 -04002462 looper.paint(), text, byteLength, xpos, constY);
Herb Derby8a6348e2018-07-12 15:30:35 -04002463 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002464 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002465 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002466
reed@google.com4e2b3d32011-04-07 14:18:59 +00002467 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002468}
2469
reed@google.come0d9ce82014-04-23 04:00:17 +00002470void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2471 const SkMatrix* matrix, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002472 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002473
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474 while (iter.next()) {
Ben Wagnerd234afd2018-04-13 15:50:01 -04002475 iter.fDevice->drawTextOnPath(text, byteLength, path, matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002476 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002477
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002478 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002479}
2480
reed45561a02016-07-07 12:47:17 -07002481void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2482 const SkRect* cullRect, const SkPaint& paint) {
2483 if (cullRect && this->quickReject(*cullRect)) {
2484 return;
2485 }
2486
Ben Wagner2c312c42018-06-27 14:46:46 -04002487 LOOPER_BEGIN(paint, nullptr)
reed45561a02016-07-07 12:47:17 -07002488
2489 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002490 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002491 }
2492
2493 LOOPER_END
2494}
2495
fmalita00d5c2c2014-08-21 08:53:26 -07002496void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2497 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002498 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002499 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002500 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002501 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002502 SkRect tmp;
2503 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2504 return;
2505 }
2506 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002507 }
2508
fmalita024f9962015-03-03 19:08:17 -08002509 // We cannot filter in the looper as we normally do, because the paint is
2510 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002511 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002512
fmalitaaa1b9122014-08-28 14:32:24 -07002513 while (iter.next()) {
Herb Derbyb983e6b2018-07-13 13:26:29 -04002514 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, SkPoint::Make(x, y));
2515 iter.fDevice->drawGlyphRunList(fScratchGlyphRunBuilder->useGlyphRunList());
fmalita00d5c2c2014-08-21 08:53:26 -07002516 }
2517
fmalitaaa1b9122014-08-28 14:32:24 -07002518 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002519}
2520
Cary Clark2a475ea2017-04-28 15:35:12 -04002521void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2522 this->drawText(string.c_str(), string.size(), x, y, paint);
2523}
2524
reed@google.come0d9ce82014-04-23 04:00:17 +00002525// These will become non-virtual, so they always call the (virtual) onDraw... method
2526void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2527 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002528 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002529 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002530 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002531 this->onDrawText(text, byteLength, x, y, paint);
2532 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002533}
2534void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2535 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002536 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002537 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002538 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002539 this->onDrawPosText(text, byteLength, pos, paint);
2540 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002541}
2542void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2543 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002544 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002545 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002546 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002547 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2548 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002549}
2550void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2551 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002552 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002553 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002554 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002555 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2556 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002557}
reed45561a02016-07-07 12:47:17 -07002558void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2559 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002560 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002561 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002562 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002563 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2564 }
2565}
fmalita00d5c2c2014-08-21 08:53:26 -07002566void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2567 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002568 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002569 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002570 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002571 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002572}
reed@google.come0d9ce82014-04-23 04:00:17 +00002573
Ruiqi Maof5101492018-06-29 14:32:21 -04002574void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkMatrix* bones,
2575 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002576 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002577
2578 while (iter.next()) {
2579 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002580 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002581 }
2582
2583 LOOPER_END
2584}
2585
dandovb3c9d1c2014-08-12 08:34:29 -07002586void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002587 const SkPoint texCoords[4], SkBlendMode bmode,
2588 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002589 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002590 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002591 return;
2592 }
mtklein6cfa73a2014-08-13 13:33:49 -07002593
Mike Reedfaba3712016-11-03 14:45:31 -04002594 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002595}
2596
2597void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002598 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002599 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002600 // Since a patch is always within the convex hull of the control points, we discard it when its
2601 // bounding rectangle is completely outside the current clip.
2602 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002603 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002604 if (this->quickReject(bounds)) {
2605 return;
2606 }
mtklein6cfa73a2014-08-13 13:33:49 -07002607
Ben Wagner2c312c42018-06-27 14:46:46 -04002608 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002609
dandovecfff212014-08-04 10:02:00 -07002610 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002611 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002612 }
mtklein6cfa73a2014-08-13 13:33:49 -07002613
dandovecfff212014-08-04 10:02:00 -07002614 LOOPER_END
2615}
2616
reeda8db7282015-07-07 10:22:31 -07002617void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002618#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002619 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002620#endif
reede3b38ce2016-01-08 09:18:44 -08002621 RETURN_ON_NULL(dr);
2622 if (x || y) {
2623 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2624 this->onDrawDrawable(dr, &matrix);
2625 } else {
2626 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002627 }
2628}
2629
reeda8db7282015-07-07 10:22:31 -07002630void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002631#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002632 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002633#endif
reede3b38ce2016-01-08 09:18:44 -08002634 RETURN_ON_NULL(dr);
2635 if (matrix && matrix->isIdentity()) {
2636 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002637 }
reede3b38ce2016-01-08 09:18:44 -08002638 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002639}
2640
2641void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002642 // drawable bounds are no longer reliable (e.g. android displaylist)
2643 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002644 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002645}
2646
reed71c3c762015-06-24 10:29:17 -07002647void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002648 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002649 const SkRect* cull, const SkPaint* paint) {
2650 if (cull && this->quickReject(*cull)) {
2651 return;
2652 }
2653
2654 SkPaint pnt;
2655 if (paint) {
2656 pnt = *paint;
2657 }
halcanary9d524f22016-03-29 09:03:52 -07002658
Ben Wagner2c312c42018-06-27 14:46:46 -04002659 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002660 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002661 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002662 }
2663 LOOPER_END
2664}
2665
reedf70b5312016-03-04 16:36:20 -08002666void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2667 SkASSERT(key);
2668
2669 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002670 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002671 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002672 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002673 }
2674 LOOPER_END
2675}
2676
reed@android.com8a1c16f2008-12-17 15:59:43 +00002677//////////////////////////////////////////////////////////////////////////////
2678// These methods are NOT virtual, and therefore must call back into virtual
2679// methods, rather than actually drawing themselves.
2680//////////////////////////////////////////////////////////////////////////////
2681
reed374772b2016-10-05 17:33:02 -07002682void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002683 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002684 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002685 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002686 this->drawPaint(paint);
2687}
2688
2689void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002690 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002691 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2692}
2693
Mike Reed3661bc92017-02-22 13:21:42 -05002694void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002695 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002696 pts[0].set(x0, y0);
2697 pts[1].set(x1, y1);
2698 this->drawPoints(kLines_PointMode, 2, pts, paint);
2699}
2700
Mike Reed3661bc92017-02-22 13:21:42 -05002701void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002702 if (radius < 0) {
2703 radius = 0;
2704 }
2705
2706 SkRect r;
2707 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002708 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002709}
2710
2711void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2712 const SkPaint& paint) {
2713 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002714 SkRRect rrect;
2715 rrect.setRectXY(r, rx, ry);
2716 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002717 } else {
2718 this->drawRect(r, paint);
2719 }
2720}
2721
reed@android.com8a1c16f2008-12-17 15:59:43 +00002722void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2723 SkScalar sweepAngle, bool useCenter,
2724 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002725 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002726 if (oval.isEmpty() || !sweepAngle) {
2727 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002728 }
bsalomon21af9ca2016-08-25 12:29:23 -07002729 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730}
2731
2732void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2733 const SkPath& path, SkScalar hOffset,
2734 SkScalar vOffset, const SkPaint& paint) {
2735 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002736
reed@android.com8a1c16f2008-12-17 15:59:43 +00002737 matrix.setTranslate(hOffset, vOffset);
2738 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2739}
2740
reed@android.comf76bacf2009-05-13 14:00:33 +00002741///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002742
Mike Klein88d90712018-01-27 17:30:04 +00002743/**
2744 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2745 * against the playback cost of recursing into the subpicture to get at its actual ops.
2746 *
2747 * For now we pick a conservatively small value, though measurement (and other heuristics like
2748 * the type of ops contained) may justify changing this value.
2749 */
2750#define kMaxPictureOpsToUnrollInsteadOfRef 1
2751
reedd5fa1a42014-08-09 11:08:05 -07002752void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002753 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002754 RETURN_ON_NULL(picture);
2755
reede3b38ce2016-01-08 09:18:44 -08002756 if (matrix && matrix->isIdentity()) {
2757 matrix = nullptr;
2758 }
Mike Klein88d90712018-01-27 17:30:04 +00002759 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2760 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2761 picture->playback(this);
2762 } else {
2763 this->onDrawPicture(picture, matrix, paint);
2764 }
reedd5fa1a42014-08-09 11:08:05 -07002765}
robertphillips9b14f262014-06-04 05:40:44 -07002766
reedd5fa1a42014-08-09 11:08:05 -07002767void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2768 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002769 if (!paint || paint->canComputeFastBounds()) {
2770 SkRect bounds = picture->cullRect();
2771 if (paint) {
2772 paint->computeFastBounds(bounds, &bounds);
2773 }
2774 if (matrix) {
2775 matrix->mapRect(&bounds);
2776 }
2777 if (this->quickReject(bounds)) {
2778 return;
2779 }
2780 }
2781
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002782 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002783 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784}
2785
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786///////////////////////////////////////////////////////////////////////////////
2787///////////////////////////////////////////////////////////////////////////////
2788
reed3aafe112016-08-18 12:45:34 -07002789SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002790 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791
2792 SkASSERT(canvas);
2793
reed3aafe112016-08-18 12:45:34 -07002794 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795 fDone = !fImpl->next();
2796}
2797
2798SkCanvas::LayerIter::~LayerIter() {
2799 fImpl->~SkDrawIter();
2800}
2801
2802void SkCanvas::LayerIter::next() {
2803 fDone = !fImpl->next();
2804}
2805
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002806SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002807 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002808}
2809
2810const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002811 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002812}
2813
2814const SkPaint& SkCanvas::LayerIter::paint() const {
2815 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002816 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817 paint = &fDefaultPaint;
2818 }
2819 return *paint;
2820}
2821
Mike Reedca37f322018-03-08 13:22:16 -05002822SkIRect SkCanvas::LayerIter::clipBounds() const {
2823 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002824}
2825
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2827int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002828
2829///////////////////////////////////////////////////////////////////////////////
2830
Brian Osman10fc6fd2018-03-02 11:01:10 -05002831// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002832static bool supported_for_raster_canvas(const SkImageInfo& info) {
2833 switch (info.alphaType()) {
2834 case kPremul_SkAlphaType:
2835 case kOpaque_SkAlphaType:
2836 break;
2837 default:
2838 return false;
2839 }
2840
2841 switch (info.colorType()) {
2842 case kAlpha_8_SkColorType:
2843 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002844 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002845 case kRGBA_F16_SkColorType:
Mike Klein37854712018-06-26 11:43:06 -04002846 case kRGBA_F32_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002847 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002848 break;
2849 default:
2850 return false;
2851 }
2852
2853 return true;
2854}
2855
Mike Reed5df49342016-11-12 08:06:55 -06002856std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002857 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002858 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002859 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002860 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002861
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002862 SkBitmap bitmap;
2863 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002864 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002865 }
Mike Reed12f77342017-11-08 11:19:52 -05002866
2867 return props ?
2868 skstd::make_unique<SkCanvas>(bitmap, *props) :
2869 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002870}
reedd5fa1a42014-08-09 11:08:05 -07002871
2872///////////////////////////////////////////////////////////////////////////////
2873
Florin Malitaee424ac2016-12-01 12:47:59 -05002874SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2875 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2876
Florin Malita439ace92016-12-02 12:05:41 -05002877SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2878 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2879
Herb Derbyefe39bc2018-05-01 17:06:20 -04002880SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002881 : INHERITED(device) {}
2882
Florin Malitaee424ac2016-12-01 12:47:59 -05002883SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2884 (void)this->INHERITED::getSaveLayerStrategy(rec);
2885 return kNoLayer_SaveLayerStrategy;
2886}
2887
2888///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002889
reed73603f32016-09-20 08:42:38 -07002890static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2891static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2892static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2893static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2894static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2895static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002896
2897///////////////////////////////////////////////////////////////////////////////////////////////////
2898
2899SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2900 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002901 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002902 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2903 SkIPoint origin = dev->getOrigin();
2904 SkMatrix ctm = this->getTotalMatrix();
2905 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2906
2907 SkIRect clip = fMCRec->fRasterClip.getBounds();
2908 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002909 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002910 clip.setEmpty();
2911 }
2912
2913 fAllocator->updateHandle(handle, ctm, clip);
2914 return handle;
2915 }
2916 return nullptr;
2917}
2918
2919static bool install(SkBitmap* bm, const SkImageInfo& info,
2920 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002921 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002922}
2923
2924SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2925 SkBitmap* bm) {
2926 SkRasterHandleAllocator::Rec rec;
2927 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2928 return nullptr;
2929 }
2930 return rec.fHandle;
2931}
2932
2933std::unique_ptr<SkCanvas>
2934SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2935 const SkImageInfo& info, const Rec* rec) {
2936 if (!alloc || !supported_for_raster_canvas(info)) {
2937 return nullptr;
2938 }
2939
2940 SkBitmap bm;
2941 Handle hndl;
2942
2943 if (rec) {
2944 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2945 } else {
2946 hndl = alloc->allocBitmap(info, &bm);
2947 }
2948 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2949}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002950
2951///////////////////////////////////////////////////////////////////////////////////////////////////
2952
2953