blob: 380195f643cc57b80f151829aba836dee4497f37 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Hal Canaryc640d0d2018-06-13 09:59:02 -04008#include "SkCanvas.h"
9
Herb Derby73fe7b02017-02-08 15:12:19 -050010#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +000011#include "SkBitmapDevice.h"
reedd5fa1a42014-08-09 11:08:05 -070012#include "SkCanvasPriv.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040013#include "SkClipOpPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070014#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070015#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDraw.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#include "SkDrawLooper.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040018#include "SkDrawable.h"
Herb Derby41f4f312018-06-06 17:45:53 +000019#include "SkGlyphCache.h"
20#include "SkGlyphRun.h"
piotaixrb5fae932014-09-24 13:03:30 -070021#include "SkImage.h"
senorblanco900c3672016-04-27 11:31:23 -070022#include "SkImageFilter.h"
23#include "SkImageFilterCache.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040024#include "SkImage_Base.h"
msarettc573a402016-08-02 08:05:56 -070025#include "SkLatticeIter.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040026#include "SkMSAN.h"
Mike Reed5df49342016-11-12 08:06:55 -060027#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080028#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000029#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050030#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070031#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070032#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070033#include "SkPatchUtils.h"
Mike Reedf441cfc2018-04-11 14:50:16 -040034#include "SkPathEffect.h"
Mike Klein88d90712018-01-27 17:30:04 +000035#include "SkPicture.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040036#include "SkRRect.h"
reed@google.com00177082011-10-12 14:34:30 +000037#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050038#include "SkRasterHandleAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080039#include "SkSpecialImage.h"
Herb Derby41f4f312018-06-06 17:45:53 +000040#include "SkStrikeCache.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040041#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000042#include "SkSurface_Base.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040043#include "SkTLazy.h"
fmalita7ba7aa72014-08-29 09:46:36 -070044#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000045#include "SkTextFormatParams.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040046#include "SkTo.h"
danakj8f757f52014-11-04 11:48:43 -080047#include "SkTraceEvent.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040048#include "SkVertices.h"
49
bungemand3ebb482015-08-05 13:57:49 -070050#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000051
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000052#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080053#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050054#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000055#endif
56
reede3b38ce2016-01-08 09:18:44 -080057#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050058#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080059
Mike Reed139e5e02017-03-08 11:29:33 -050060///////////////////////////////////////////////////////////////////////////////////////////////////
61
reedc83a2972015-07-16 07:40:45 -070062/*
63 * Return true if the drawing this rect would hit every pixels in the canvas.
64 *
65 * Returns false if
66 * - rect does not contain the canvas' bounds
67 * - paint is not fill
68 * - paint would blur or otherwise change the coverage of the rect
69 */
70bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
71 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070072 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
73 (int)kNone_ShaderOverrideOpacity,
74 "need_matching_enums0");
75 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
76 (int)kOpaque_ShaderOverrideOpacity,
77 "need_matching_enums1");
78 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
79 (int)kNotOpaque_ShaderOverrideOpacity,
80 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070081
82 const SkISize size = this->getBaseLayerSize();
83 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050084
85 // if we're clipped at all, we can't overwrite the entire surface
86 {
87 SkBaseDevice* base = this->getDevice();
88 SkBaseDevice* top = this->getTopDevice();
89 if (base != top) {
90 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
91 }
92 if (!base->clipIsWideOpen()) {
93 return false;
94 }
reedc83a2972015-07-16 07:40:45 -070095 }
96
97 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070098 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070099 return false; // conservative
100 }
halcanaryc5769b22016-08-10 07:13:21 -0700101
102 SkRect devRect;
103 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
104 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700105 return false;
106 }
107 }
108
109 if (paint) {
110 SkPaint::Style paintStyle = paint->getStyle();
111 if (!(paintStyle == SkPaint::kFill_Style ||
112 paintStyle == SkPaint::kStrokeAndFill_Style)) {
113 return false;
114 }
115 if (paint->getMaskFilter() || paint->getLooper()
116 || paint->getPathEffect() || paint->getImageFilter()) {
117 return false; // conservative
118 }
119 }
120 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
121}
122
123///////////////////////////////////////////////////////////////////////////////////////////////////
124
reed@google.comda17f752012-08-16 18:27:05 +0000125// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126//#define SK_TRACE_SAVERESTORE
127
128#ifdef SK_TRACE_SAVERESTORE
129 static int gLayerCounter;
130 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
131 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
132
133 static int gRecCounter;
134 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
135 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
136
137 static int gCanvasCounter;
138 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
139 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
140#else
141 #define inc_layer()
142 #define dec_layer()
143 #define inc_rec()
144 #define dec_rec()
145 #define inc_canvas()
146 #define dec_canvas()
147#endif
148
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000149typedef SkTLazy<SkPaint> SkLazyPaint;
150
reedc83a2972015-07-16 07:40:45 -0700151void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000152 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700153 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
154 ? SkSurface::kDiscard_ContentChangeMode
155 : SkSurface::kRetain_ContentChangeMode);
156 }
157}
158
159void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
160 ShaderOverrideOpacity overrideOpacity) {
161 if (fSurfaceBase) {
162 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
163 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
164 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
165 // and therefore we don't care which mode we're in.
166 //
167 if (fSurfaceBase->outstandingImageSnapshot()) {
168 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
169 mode = SkSurface::kDiscard_ContentChangeMode;
170 }
171 }
172 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000173 }
174}
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000178/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 The clip/matrix/proc are fields that reflect the top of the save/restore
180 stack. Whenever the canvas changes, it marks a dirty flag, and then before
181 these are used (assuming we're not on a layer) we rebuild these cache
182 values: they reflect the top of the save stack, but translated and clipped
183 by the device's XY offset and bitmap-bounds.
184*/
185struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400186 DeviceCM* fNext;
187 sk_sp<SkBaseDevice> fDevice;
188 SkRasterClip fClip;
189 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
190 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400191 sk_sp<SkImage> fClipImage;
192 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193
Florin Malita53f77bd2017-04-28 13:48:37 -0400194 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000195 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700196 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400197 , fDevice(std::move(device))
198 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700199 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000200 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400201 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400202 {}
reed@google.com4b226022011-01-11 18:32:13 +0000203
mtkleinfeaadee2015-04-08 11:25:48 -0700204 void reset(const SkIRect& bounds) {
205 SkASSERT(!fPaint);
206 SkASSERT(!fNext);
207 SkASSERT(fDevice);
208 fClip.setRect(bounds);
209 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210};
211
212/* This is the record we keep for each save/restore level in the stack.
213 Since a level optionally copies the matrix and/or stack, we have pointers
214 for these fields. If the value is copied for this level, the copy is
215 stored in the ...Storage field, and the pointer points to that. If the
216 value is not copied for this level, we ignore ...Storage, and just point
217 at the corresponding value in the previous level in the stack.
218*/
219class SkCanvas::MCRec {
220public:
reedd9544982014-09-09 18:46:22 -0700221 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 /* If there are any layers in the stack, this points to the top-most
223 one that is at or below this level in the stack (so we know what
224 bitmap/device to draw into from this level. This value is NOT
225 reference counted, since the real owner is either our fLayer field,
226 or a previous one in a lower level.)
227 */
Mike Reeda1361362017-03-07 09:37:29 -0500228 DeviceCM* fTopLayer;
229 SkConservativeClip fRasterClip;
230 SkMatrix fMatrix;
231 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232
Mike Reeda1361362017-03-07 09:37:29 -0500233 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700234 fLayer = nullptr;
235 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800236 fMatrix.reset();
237 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700238
reedd9544982014-09-09 18:46:22 -0700239 // don't bother initializing fNext
240 inc_rec();
241 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400242 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
halcanary96fcdcc2015-08-27 07:41:13 -0700243 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700244 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800245 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700246
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 // don't bother initializing fNext
248 inc_rec();
249 }
250 ~MCRec() {
halcanary385fe4d2015-08-26 13:07:48 -0700251 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 dec_rec();
253 }
mtkleinfeaadee2015-04-08 11:25:48 -0700254
255 void reset(const SkIRect& bounds) {
256 SkASSERT(fLayer);
257 SkASSERT(fDeferredSaveCount == 0);
258
259 fMatrix.reset();
260 fRasterClip.setRect(bounds);
261 fLayer->reset(bounds);
262 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263};
264
Mike Reeda1361362017-03-07 09:37:29 -0500265class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266public:
Mike Reeda1361362017-03-07 09:37:29 -0500267 SkDrawIter(SkCanvas* canvas)
268 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
269 {}
reed@google.com4b226022011-01-11 18:32:13 +0000270
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000272 const DeviceCM* rec = fCurrLayer;
273 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400274 fDevice = rec->fDevice.get();
275 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700277 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 return true;
279 }
280 return false;
281 }
reed@google.com4b226022011-01-11 18:32:13 +0000282
reed@google.com6f8f2922011-03-04 22:27:10 +0000283 int getX() const { return fDevice->getOrigin().x(); }
284 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000286
Mike Reed99330ba2017-02-22 11:01:08 -0500287 SkBaseDevice* fDevice;
288
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 const DeviceCM* fCurrLayer;
291 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292};
293
Florin Malita713b8ef2017-04-28 10:57:24 -0400294#define FOR_EACH_TOP_DEVICE( code ) \
295 do { \
296 DeviceCM* layer = fMCRec->fTopLayer; \
297 while (layer) { \
298 SkBaseDevice* device = layer->fDevice.get(); \
299 if (device) { \
300 code; \
301 } \
302 layer = layer->fNext; \
303 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500304 } while (0)
305
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306/////////////////////////////////////////////////////////////////////////////
307
reeddbc3cef2015-04-29 12:18:57 -0700308static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
309 return lazy->isValid() ? lazy->get() : lazy->set(orig);
310}
311
312/**
313 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700314 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700315 */
reedd053ce92016-03-22 10:17:23 -0700316static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700317 SkImageFilter* imgf = paint.getImageFilter();
318 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700319 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700320 }
321
reedd053ce92016-03-22 10:17:23 -0700322 SkColorFilter* imgCFPtr;
323 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700324 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700325 }
reedd053ce92016-03-22 10:17:23 -0700326 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700327
328 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700329 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700330 // there is no existing paint colorfilter, so we can just return the imagefilter's
331 return imgCF;
332 }
333
334 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
335 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500336 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700337}
338
senorblanco87e066e2015-10-28 11:23:36 -0700339/**
340 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
341 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
342 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
343 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
344 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
345 * conservative "effective" bounds based on the settings in the paint... with one exception. This
346 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
347 * deliberately ignored.
348 */
349static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
350 const SkRect& rawBounds,
351 SkRect* storage) {
352 SkPaint tmpUnfiltered(paint);
353 tmpUnfiltered.setImageFilter(nullptr);
354 if (tmpUnfiltered.canComputeFastBounds()) {
355 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
356 } else {
357 return rawBounds;
358 }
359}
360
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361class AutoDrawLooper {
362public:
senorblanco87e066e2015-10-28 11:23:36 -0700363 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
364 // paint. It's used to determine the size of the offscreen layer for filters.
365 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700366 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700367 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000368 fCanvas = canvas;
reed4a8126e2014-09-22 07:29:03 -0700369 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000370 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700371 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000372 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373
reedd053ce92016-03-22 10:17:23 -0700374 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700375 if (simplifiedCF) {
376 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700377 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700378 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700379 fPaint = paint;
380 }
381
382 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700383 /**
384 * We implement ImageFilters for a given draw by creating a layer, then applying the
385 * imagefilter to the pixels of that layer (its backing surface/image), and then
386 * we call restore() to xfer that layer to the main canvas.
387 *
388 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
389 * 2. Generate the src pixels:
390 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
391 * return (fPaint). We then draw the primitive (using srcover) into a cleared
392 * buffer/surface.
393 * 3. Restore the layer created in #1
394 * The imagefilter is passed the buffer/surface from the layer (now filled with the
395 * src pixels of the primitive). It returns a new "filtered" buffer, which we
396 * draw onto the previous layer using the xfermode from the original paint.
397 */
reed@google.com8926b162012-03-23 15:36:36 +0000398 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500399 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700400 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700401 SkRect storage;
402 if (rawBounds) {
403 // Make rawBounds include all paint outsets except for those due to image filters.
404 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
405 }
reedbfd5f172016-01-07 11:28:08 -0800406 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700407 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700408 fTempLayerForImageFilter = true;
409 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000410 }
411
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000412 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500413 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000414 fIsSimple = false;
415 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700416 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000417 // can we be marked as simple?
Ben Wagner2c312c42018-06-27 14:46:46 -0400418 fIsSimple = !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000419 }
420 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000421
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700423 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000424 fCanvas->internalRestore();
425 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000426 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000428
reed@google.com4e2b3d32011-04-07 14:18:59 +0000429 const SkPaint& paint() const {
430 SkASSERT(fPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400431 SkASSERT(fPaint->getDrawLooper() == nullptr); // we should have cleared this
reed@google.com4e2b3d32011-04-07 14:18:59 +0000432 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000434
Ben Wagner2c312c42018-06-27 14:46:46 -0400435 bool next() {
reed@google.com129ec222012-05-15 13:24:09 +0000436 if (fDone) {
437 return false;
438 } else if (fIsSimple) {
439 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000440 return !fPaint->nothingToDraw();
441 } else {
Ben Wagner2c312c42018-06-27 14:46:46 -0400442 return this->doNext();
reed@google.com129ec222012-05-15 13:24:09 +0000443 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000444 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000445
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500447 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700448 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000449 SkCanvas* fCanvas;
450 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000451 const SkPaint* fPaint;
452 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700453 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000454 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000455 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000456 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400457 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000458
Ben Wagner2c312c42018-06-27 14:46:46 -0400459 bool doNext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460};
461
Ben Wagner2c312c42018-06-27 14:46:46 -0400462bool AutoDrawLooper::doNext() {
halcanary96fcdcc2015-08-27 07:41:13 -0700463 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000464 SkASSERT(!fIsSimple);
Ben Wagner2c312c42018-06-27 14:46:46 -0400465 SkASSERT(fLooperContext || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000466
reeddbc3cef2015-04-29 12:18:57 -0700467 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
468 *fLazyPaintInit.get() : fOrigPaint);
Mike Reeddd8ae142018-04-12 11:05:01 -0400469 // never want our downstream clients (i.e. devices) to see loopers
470 paint->setDrawLooper(nullptr);
reed@google.com129ec222012-05-15 13:24:09 +0000471
reed5c476fb2015-04-20 08:04:21 -0700472 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700473 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700474 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000475 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000476
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000477 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000478 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000479 return false;
480 }
reed@google.com129ec222012-05-15 13:24:09 +0000481 fPaint = paint;
482
483 // if we only came in here for the imagefilter, mark us as done
Ben Wagner2c312c42018-06-27 14:46:46 -0400484 if (!fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000485 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000486 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000487 return true;
488}
489
reed@android.com8a1c16f2008-12-17 15:59:43 +0000490////////// macros to place around the internal draw calls //////////////////
491
reed3aafe112016-08-18 12:45:34 -0700492#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
493 this->predrawNotify(); \
494 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400495 while (looper.next()) { \
reed262a71b2015-12-05 13:07:27 -0800496 SkDrawIter iter(this);
497
498
Ben Wagner2c312c42018-06-27 14:46:46 -0400499#define LOOPER_BEGIN_DRAWDEVICE(paint) \
reed@google.com97af1a62012-08-28 12:19:02 +0000500 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700501 AutoDrawLooper looper(this, paint, true); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400502 while (looper.next()) { \
reed@google.com8926b162012-03-23 15:36:36 +0000503 SkDrawIter iter(this);
504
Ben Wagner2c312c42018-06-27 14:46:46 -0400505#define LOOPER_BEGIN(paint, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000506 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700507 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400508 while (looper.next()) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000510
Ben Wagner2c312c42018-06-27 14:46:46 -0400511#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, bounds, auxOpaque) \
reedc83a2972015-07-16 07:40:45 -0700512 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700513 AutoDrawLooper looper(this, paint, false, bounds); \
Ben Wagner2c312c42018-06-27 14:46:46 -0400514 while (looper.next()) { \
reedc83a2972015-07-16 07:40:45 -0700515 SkDrawIter iter(this);
516
reed@google.com4e2b3d32011-04-07 14:18:59 +0000517#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000518
519////////////////////////////////////////////////////////////////////////////
520
msarettfbfa2582016-08-12 08:29:08 -0700521static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
522 if (bounds.isEmpty()) {
523 return SkRect::MakeEmpty();
524 }
525
526 // Expand bounds out by 1 in case we are anti-aliasing. We store the
527 // bounds as floats to enable a faster quick reject implementation.
528 SkRect dst;
529 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
530 return dst;
531}
532
mtkleinfeaadee2015-04-08 11:25:48 -0700533void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
534 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700535 fMCRec->reset(bounds);
536
537 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500538 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400539 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700540 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700541 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700542}
543
Hal Canary363a3f82018-10-04 11:04:48 -0400544void SkCanvas::init(sk_sp<SkBaseDevice> device) {
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000545 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800546 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700547 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000548
549 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500550 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500551 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700552 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553
reeda499f902015-05-01 09:34:31 -0700554 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
555 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Herb Derbyefe39bc2018-05-01 17:06:20 -0400556 new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700557
reed@android.com8a1c16f2008-12-17 15:59:43 +0000558 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000559
halcanary96fcdcc2015-08-27 07:41:13 -0700560 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000561
reedf92c8662014-08-18 08:02:43 -0700562 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700563 // The root device and the canvas should always have the same pixel geometry
564 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800565 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700566 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500567
Mike Reedc42a1cd2017-02-14 14:25:14 -0500568 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700569 }
Herb Derby4ffa0272018-06-04 15:49:15 -0400570
Herb Derby59d997a2018-06-07 12:44:09 -0400571 fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000572}
573
reed@google.comcde92112011-07-06 20:00:52 +0000574SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000575 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700576 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000577{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000578 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000579
Hal Canary363a3f82018-10-04 11:04:48 -0400580 this->init(nullptr);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000581}
582
reed96a857e2015-01-25 10:33:58 -0800583SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000584 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800585 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000586{
587 inc_canvas();
Herb Derbyefe39bc2018-05-01 17:06:20 -0400588 this->init(sk_make_sp<SkNoPixelsDevice>(
Hal Canary363a3f82018-10-04 11:04:48 -0400589 SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps));
reedd9544982014-09-09 18:46:22 -0700590}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000591
Hal Canary363a3f82018-10-04 11:04:48 -0400592SkCanvas::SkCanvas(const SkIRect& bounds)
reedd9544982014-09-09 18:46:22 -0700593 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700594 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700595{
596 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700597
Mike Reed566e53c2017-03-10 10:49:45 -0500598 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
Hal Canary363a3f82018-10-04 11:04:48 -0400599 this->init(sk_make_sp<SkNoPixelsDevice>(r, fProps));
reedd9544982014-09-09 18:46:22 -0700600}
601
Herb Derbyefe39bc2018-05-01 17:06:20 -0400602SkCanvas::SkCanvas(sk_sp<SkBaseDevice> device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000603 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700604 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000605{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000606 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700607
Hal Canary363a3f82018-10-04 11:04:48 -0400608 this->init(device);
robertphillipsfcf78292015-06-19 11:49:52 -0700609}
610
reed4a8126e2014-09-22 07:29:03 -0700611SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700612 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700613 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700614{
615 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700616
Mike Reed910ca0f2018-04-25 13:04:05 -0400617 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400618 this->init(device);
reed4a8126e2014-09-22 07:29:03 -0700619}
reed29c857d2014-09-21 10:25:07 -0700620
Mike Reed356f7c22017-01-10 11:58:39 -0500621SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
622 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700623 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
624 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500625 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700626{
627 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700628
Mike Reed910ca0f2018-04-25 13:04:05 -0400629 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400630 this->init(device);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000631}
632
Mike Reed356f7c22017-01-10 11:58:39 -0500633SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
634
Matt Sarett31f99ce2017-04-11 08:46:01 -0400635#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
636SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
637 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
638 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
639 , fAllocator(nullptr)
640{
641 inc_canvas();
642
643 SkBitmap tmp(bitmap);
644 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
Mike Reedc247a4e2018-04-25 15:40:09 -0400645 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr, nullptr));
Hal Canary363a3f82018-10-04 11:04:48 -0400646 this->init(device);
Matt Sarett31f99ce2017-04-11 08:46:01 -0400647}
648#endif
649
reed@android.com8a1c16f2008-12-17 15:59:43 +0000650SkCanvas::~SkCanvas() {
651 // free up the contents of our deque
652 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000653
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654 this->internalRestore(); // restore the last, since we're going away
655
halcanary385fe4d2015-08-26 13:07:48 -0700656 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000657
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658 dec_canvas();
659}
660
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000661SkMetaData& SkCanvas::getMetaData() {
662 // metadata users are rare, so we lazily allocate it. If that changes we
663 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700664 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000665 fMetaData = new SkMetaData;
666 }
667 return *fMetaData;
668}
669
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670///////////////////////////////////////////////////////////////////////////////
671
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000672void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700673 this->onFlush();
674}
675
676void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000677 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000678 if (device) {
679 device->flush();
680 }
681}
682
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000683SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000684 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000685 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
686}
687
senorblancoafc7cce2016-02-02 18:44:15 -0800688SkIRect SkCanvas::getTopLayerBounds() const {
689 SkBaseDevice* d = this->getTopDevice();
690 if (!d) {
691 return SkIRect::MakeEmpty();
692 }
693 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
694}
695
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000696SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000698 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400700 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000701}
702
Florin Malita0ed3b642017-01-13 16:56:38 +0000703SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400704 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000705}
706
Mike Reed353196f2017-07-21 11:01:18 -0400707bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000708 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400709 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000710}
711
Mike Reed353196f2017-07-21 11:01:18 -0400712bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
713 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400714}
715
716bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
717 SkPixmap pm;
718 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
719}
720
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000721bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400722 SkPixmap pm;
723 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700724 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000725 }
726 return false;
727}
728
Matt Sarett03dd6d52017-01-23 12:15:09 -0500729bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000730 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000731 SkBaseDevice* device = this->getDevice();
732 if (!device) {
733 return false;
734 }
735
Matt Sarett03dd6d52017-01-23 12:15:09 -0500736 // This check gives us an early out and prevents generation ID churn on the surface.
737 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
738 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
739 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
740 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000741 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000742
Matt Sarett03dd6d52017-01-23 12:15:09 -0500743 // Tell our owning surface to bump its generation ID.
744 const bool completeOverwrite =
745 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700746 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700747
Matt Sarett03dd6d52017-01-23 12:15:09 -0500748 // This can still fail, most notably in the case of a invalid color type or alpha type
749 // conversion. We could pull those checks into this function and avoid the unnecessary
750 // generation ID bump. But then we would be performing those checks twice, since they
751 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400752 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000753}
reed@google.com51df9e32010-12-23 19:29:18 +0000754
reed@android.com8a1c16f2008-12-17 15:59:43 +0000755//////////////////////////////////////////////////////////////////////////////
756
reed2ff1fce2014-12-11 07:07:37 -0800757void SkCanvas::checkForDeferredSave() {
758 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800759 this->doSave();
760 }
761}
762
reedf0090cb2014-11-26 08:55:51 -0800763int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800764#ifdef SK_DEBUG
765 int count = 0;
766 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
767 for (;;) {
768 const MCRec* rec = (const MCRec*)iter.next();
769 if (!rec) {
770 break;
771 }
772 count += 1 + rec->fDeferredSaveCount;
773 }
774 SkASSERT(count == fSaveCount);
775#endif
776 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800777}
778
779int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800780 fSaveCount += 1;
781 fMCRec->fDeferredSaveCount += 1;
782 return this->getSaveCount() - 1; // return our prev value
783}
784
785void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800786 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700787
788 SkASSERT(fMCRec->fDeferredSaveCount > 0);
789 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800790 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800791}
792
793void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800794 if (fMCRec->fDeferredSaveCount > 0) {
795 SkASSERT(fSaveCount > 1);
796 fSaveCount -= 1;
797 fMCRec->fDeferredSaveCount -= 1;
798 } else {
799 // check for underflow
800 if (fMCStack.count() > 1) {
801 this->willRestore();
802 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700803 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800804 this->internalRestore();
805 this->didRestore();
806 }
reedf0090cb2014-11-26 08:55:51 -0800807 }
808}
809
810void SkCanvas::restoreToCount(int count) {
811 // sanity check
812 if (count < 1) {
813 count = 1;
814 }
mtkleinf0f14112014-12-12 08:46:25 -0800815
reedf0090cb2014-11-26 08:55:51 -0800816 int n = this->getSaveCount() - count;
817 for (int i = 0; i < n; ++i) {
818 this->restore();
819 }
820}
821
reed2ff1fce2014-12-11 07:07:37 -0800822void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700824 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000826
Mike Reedc42a1cd2017-02-14 14:25:14 -0500827 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828}
829
reed4960eee2015-12-18 07:09:18 -0800830bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400831 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000832}
833
reed4960eee2015-12-18 07:09:18 -0800834bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700835 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500836 SkIRect clipBounds = this->getDeviceClipBounds();
837 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000838 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000839 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000840
reed96e657d2015-03-10 17:30:07 -0700841 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
842
Robert Phillips12078432018-05-17 11:17:39 -0400843 if (imageFilter && bounds && !imageFilter->canComputeFastBounds()) {
844 // If the image filter DAG affects transparent black then we will need to render
845 // out to the clip bounds
846 bounds = nullptr;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000847 }
Robert Phillips12078432018-05-17 11:17:39 -0400848
849 SkIRect inputSaveLayerBounds;
bsalomon49f085d2014-09-05 13:34:00 -0700850 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700852 ctm.mapRect(&r, *bounds);
Robert Phillips12078432018-05-17 11:17:39 -0400853 r.roundOut(&inputSaveLayerBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000854 } else { // no user bounds, so just use the clip
Robert Phillips12078432018-05-17 11:17:39 -0400855 inputSaveLayerBounds = clipBounds;
856 }
857
858 if (imageFilter) {
859 // expand the clip bounds by the image filter DAG to include extra content that might
860 // be required by the image filters.
861 clipBounds = imageFilter->filterBounds(clipBounds, ctm,
862 SkImageFilter::kReverse_MapDirection,
863 &inputSaveLayerBounds);
864 }
865
866 SkIRect clippedSaveLayerBounds;
867 if (bounds) {
868 // For better or for worse, user bounds currently act as a hard clip on the layer's
869 // extent (i.e., they implement the CSS filter-effects 'filter region' feature).
870 clippedSaveLayerBounds = inputSaveLayerBounds;
871 } else {
872 // If there are no user bounds, we don't want to artificially restrict the resulting
873 // layer bounds, so allow the expanded clip bounds free reign.
874 clippedSaveLayerBounds = clipBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000875 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800876
877 // early exit if the layer's bounds are clipped out
Robert Phillips12078432018-05-17 11:17:39 -0400878 if (!clippedSaveLayerBounds.intersect(clipBounds)) {
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800879 if (BoundsAffectsClip(saveLayerFlags)) {
880 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
881 fMCRec->fRasterClip.setEmpty();
882 fDeviceClipBounds.setEmpty();
883 }
884 return false;
885 }
Robert Phillips12078432018-05-17 11:17:39 -0400886 SkASSERT(!clippedSaveLayerBounds.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000887
reed4960eee2015-12-18 07:09:18 -0800888 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700889 // Simplify the current clips since they will be applied properly during restore()
Robert Phillips12078432018-05-17 11:17:39 -0400890 fMCRec->fRasterClip.setRect(clippedSaveLayerBounds);
891 fDeviceClipBounds = qr_clip_bounds(clippedSaveLayerBounds);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000892 }
893
894 if (intersection) {
Robert Phillips12078432018-05-17 11:17:39 -0400895 *intersection = clippedSaveLayerBounds;
junov@chromium.orga907ac32012-02-24 21:54:07 +0000896 }
Robert Phillips12078432018-05-17 11:17:39 -0400897
junov@chromium.orga907ac32012-02-24 21:54:07 +0000898 return true;
899}
900
reed4960eee2015-12-18 07:09:18 -0800901int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
902 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000903}
904
reed70ee31b2015-12-10 13:44:45 -0800905int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800906 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
907}
908
Cary Clarke041e312018-03-06 13:00:52 -0500909int SkCanvas::saveLayer(const SaveLayerRec& rec) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700910 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed49f8da02018-08-27 10:48:52 -0400911 if (rec.fPaint && rec.fPaint->nothingToDraw()) {
912 // no need for the layer (or any of the draws until the matching restore()
913 this->save();
914 this->clipRect({0,0,0,0});
915 } else {
916 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
917 fSaveCount += 1;
918 this->internalSaveLayer(rec, strategy);
919 }
reed4960eee2015-12-18 07:09:18 -0800920 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800921}
922
reeda2217ef2016-07-20 06:04:34 -0700923void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500924 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500925 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700926 SkDraw draw;
927 SkRasterClip rc;
928 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
929 if (!dst->accessPixels(&draw.fDst)) {
930 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800931 }
reeda2217ef2016-07-20 06:04:34 -0700932 draw.fMatrix = &SkMatrix::I();
933 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800934
935 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500936 if (filter) {
937 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
938 }
reeda2217ef2016-07-20 06:04:34 -0700939
Mike Reedc42a1cd2017-02-14 14:25:14 -0500940 int x = src->getOrigin().x() - dstOrigin.x();
941 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700942 auto special = src->snapSpecial();
943 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400944 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700945 }
robertphillips7354a4b2015-12-16 05:08:27 -0800946}
reed70ee31b2015-12-10 13:44:45 -0800947
Mike Kleine083f7c2018-02-07 12:54:27 -0500948static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500949 // Need to force L32 for now if we have an image filter.
950 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
951 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500952 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800953 }
Mike Klein649fb732018-02-26 15:09:16 -0500954
955 SkColorType ct = prev.colorType();
956 if (prev.bytesPerPixel() <= 4) {
957 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
958 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
959 ct = kN32_SkColorType;
960 }
961 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800962}
963
reed4960eee2015-12-18 07:09:18 -0800964void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
Yuqian Lif7c723c2018-08-29 16:25:47 -0700965 TRACE_EVENT0("skia", TRACE_FUNC);
reed4960eee2015-12-18 07:09:18 -0800966 const SkRect* bounds = rec.fBounds;
967 const SkPaint* paint = rec.fPaint;
968 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
969
reed8c30a812016-04-20 16:36:51 -0700970 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400971 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700972 SkMatrix stashedMatrix = fMCRec->fMatrix;
Robert Phillips3d0e8502018-04-20 10:27:27 -0400973 MCRec* modifiedRec = nullptr;
reed8c30a812016-04-20 16:36:51 -0700974 SkMatrix remainder;
975 SkSize scale;
976 /*
977 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
978 * but they do handle scaling. To accommodate this, we do the following:
979 *
980 * 1. Stash off the current CTM
981 * 2. Decompose the CTM into SCALE and REMAINDER
982 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
983 * contains the REMAINDER
984 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
985 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
986 * of the original imagefilter, and draw that (via drawSprite)
987 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
988 *
989 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
990 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
991 */
reed96a04f32016-04-25 09:25:15 -0700992 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -0700993 stashedMatrix.decomposeScale(&scale, &remainder))
994 {
995 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
Robert Phillips3d0e8502018-04-20 10:27:27 -0400996 modifiedRec = fMCRec;
reed8c30a812016-04-20 16:36:51 -0700997 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
998 SkPaint* p = lazyP.set(*paint);
999 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1000 SkFilterQuality::kLow_SkFilterQuality,
1001 sk_ref_sp(imageFilter)));
1002 imageFilter = p->getImageFilter();
1003 paint = p;
1004 }
reed8c30a812016-04-20 16:36:51 -07001005
junov@chromium.orga907ac32012-02-24 21:54:07 +00001006 // do this before we create the layer. We don't call the public save() since
1007 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001008 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001009
junov@chromium.orga907ac32012-02-24 21:54:07 +00001010 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001011 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
Robert Phillips3d0e8502018-04-20 10:27:27 -04001012 if (modifiedRec) {
1013 // In this case there will be no layer in which to stash the matrix so we need to
1014 // revert the prior MCRec to its earlier state.
1015 modifiedRec->fMatrix = stashedMatrix;
1016 }
reed2ff1fce2014-12-11 07:07:37 -08001017 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001018 }
1019
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001020 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1021 // the clipRectBounds() call above?
1022 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001023 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001024 }
1025
reed8dc0ccb2015-03-20 06:32:52 -07001026 SkPixelGeometry geo = fProps.pixelGeometry();
1027 if (paint) {
reed76033be2015-03-14 10:54:31 -07001028 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001029 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001030 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001031 }
1032 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001033
robertphillips5139e502016-07-19 05:10:40 -07001034 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001035 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001036 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001037 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001038 }
reedb2db8982014-11-13 12:41:02 -08001039
Mike Kleine083f7c2018-02-07 12:54:27 -05001040 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001041
Hal Canary704cd322016-11-07 14:13:52 -05001042 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001043 {
reed70ee31b2015-12-10 13:44:45 -08001044 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001045 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001046 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
Herb Derby41f4f312018-06-06 17:45:53 +00001047 const bool trackCoverage =
1048 SkToBool(saveLayerFlags & kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag);
reed70ee31b2015-12-10 13:44:45 -08001049 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001050 preserveLCDText,
Mike Reed910ca0f2018-04-25 13:04:05 -04001051 trackCoverage,
Mike Reed356f7c22017-01-10 11:58:39 -05001052 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001053 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1054 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001055 return;
reed61f501f2015-04-29 08:34:00 -07001056 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001057 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001058 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059
Mike Reedb43a3e02017-02-11 10:18:58 -05001060 // only have a "next" if this new layer doesn't affect the clip (rare)
1061 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062 fMCRec->fLayer = layer;
1063 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001064
Mike Reedc61abee2017-02-28 17:45:27 -05001065 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001066 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001067 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001068 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001069
Mike Reedc42a1cd2017-02-14 14:25:14 -05001070 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1071
1072 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1073 if (layer->fNext) {
1074 // need to punch a hole in the previous device, so we don't draw there, given that
1075 // the new top-layer will allow drawing to happen "below" it.
1076 SkRegion hole(ir);
1077 do {
1078 layer = layer->fNext;
1079 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1080 } while (layer->fNext);
1081 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001082}
1083
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001084int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001085 if (0xFF == alpha) {
1086 return this->saveLayer(bounds, nullptr);
1087 } else {
1088 SkPaint tmpPaint;
1089 tmpPaint.setAlpha(alpha);
1090 return this->saveLayer(bounds, &tmpPaint);
1091 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001092}
1093
reed@android.com8a1c16f2008-12-17 15:59:43 +00001094void SkCanvas::internalRestore() {
1095 SkASSERT(fMCStack.count() != 0);
1096
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001097 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098 DeviceCM* layer = fMCRec->fLayer; // may be null
1099 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001100 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101
1102 // now do the normal restore()
1103 fMCRec->~MCRec(); // balanced in save()
1104 fMCStack.pop_back();
1105 fMCRec = (MCRec*)fMCStack.back();
1106
Mike Reedc42a1cd2017-02-14 14:25:14 -05001107 if (fMCRec) {
1108 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1109 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001110
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1112 since if we're being recorded, we don't want to record this (the
1113 recorder will have already recorded the restore).
1114 */
bsalomon49f085d2014-09-05 13:34:00 -07001115 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001116 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001117 const SkIPoint& origin = layer->fDevice->getOrigin();
Lee Salzman5d8949c2018-09-19 15:36:54 -04001118 layer->fDevice->setImmutable();
Florin Malita713b8ef2017-04-28 10:57:24 -04001119 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001120 layer->fPaint.get(),
1121 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001122 // restore what we smashed in internalSaveLayer
Ben Wagner738a2562018-04-23 17:23:30 -04001123 this->internalSetMatrix(layer->fStashedMatrix);
reed@google.com8926b162012-03-23 15:36:36 +00001124 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001125 delete layer;
reedb679ca82015-04-07 04:40:48 -07001126 } else {
1127 // we're at the root
reeda499f902015-05-01 09:34:31 -07001128 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001129 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001130 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001131 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001132 }
msarettfbfa2582016-08-12 08:29:08 -07001133
1134 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001135 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001136 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1137 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001138}
1139
reede8f30622016-03-23 18:59:25 -07001140sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001141 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001142 props = &fProps;
1143 }
1144 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001145}
1146
reede8f30622016-03-23 18:59:25 -07001147sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001148 SkBaseDevice* dev = this->getDevice();
Cary Clarka24712e2018-09-05 18:41:40 +00001149 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001150}
1151
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001152SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001153 return this->onImageInfo();
1154}
1155
1156SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001157 SkBaseDevice* dev = this->getDevice();
1158 if (dev) {
1159 return dev->imageInfo();
1160 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001161 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001162 }
1163}
1164
brianosman898235c2016-04-06 07:38:23 -07001165bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001166 return this->onGetProps(props);
1167}
1168
1169bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001170 SkBaseDevice* dev = this->getDevice();
1171 if (dev) {
1172 if (props) {
1173 *props = fProps;
1174 }
1175 return true;
1176 } else {
1177 return false;
1178 }
1179}
1180
reed6ceeebd2016-03-09 14:26:26 -08001181bool SkCanvas::peekPixels(SkPixmap* pmap) {
1182 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001183}
1184
reed884e97c2015-05-26 11:31:54 -07001185bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001186 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001187 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001188}
1189
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001190void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001191 SkPixmap pmap;
1192 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001193 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001194 }
1195 if (info) {
1196 *info = pmap.info();
1197 }
1198 if (rowBytes) {
1199 *rowBytes = pmap.rowBytes();
1200 }
1201 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001202 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001203 }
reed884e97c2015-05-26 11:31:54 -07001204 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001205}
1206
reed884e97c2015-05-26 11:31:54 -07001207bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001208 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001209 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001210}
1211
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001213
Florin Malita53f77bd2017-04-28 13:48:37 -04001214void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1215 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001217 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218 paint = &tmp;
1219 }
reed@google.com4b226022011-01-11 18:32:13 +00001220
Ben Wagner2c312c42018-06-27 14:46:46 -04001221 LOOPER_BEGIN_DRAWDEVICE(*paint)
reeda2217ef2016-07-20 06:04:34 -07001222
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001224 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001225 paint = &looper.paint();
1226 SkImageFilter* filter = paint->getImageFilter();
1227 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001228 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001229 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1230 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001231 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1232 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001233 }
reed@google.com76dd2772012-01-05 21:15:07 +00001234 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001235 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001236 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001237 }
reeda2217ef2016-07-20 06:04:34 -07001238
reed@google.com4e2b3d32011-04-07 14:18:59 +00001239 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240}
1241
reed32704672015-12-16 08:27:10 -08001242/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001243
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001244void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001245 if (dx || dy) {
1246 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001247 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001248
reedfe69b502016-09-12 06:31:48 -07001249 // Translate shouldn't affect the is-scale-translateness of the matrix.
1250 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001251
Mike Reedc42a1cd2017-02-14 14:25:14 -05001252 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001253
reedfe69b502016-09-12 06:31:48 -07001254 this->didTranslate(dx,dy);
1255 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001256}
1257
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001258void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001259 SkMatrix m;
1260 m.setScale(sx, sy);
1261 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001262}
1263
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001264void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001265 SkMatrix m;
1266 m.setRotate(degrees);
1267 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001268}
1269
bungeman7438bfc2016-07-12 15:01:19 -07001270void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1271 SkMatrix m;
1272 m.setRotate(degrees, px, py);
1273 this->concat(m);
1274}
1275
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001276void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001277 SkMatrix m;
1278 m.setSkew(sx, sy);
1279 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001280}
1281
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001282void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001283 if (matrix.isIdentity()) {
1284 return;
1285 }
1286
reed2ff1fce2014-12-11 07:07:37 -08001287 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001288 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001289 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001290
Mike Reed7627fa52017-02-08 10:07:53 -05001291 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001292
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001293 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001294}
1295
reed8c30a812016-04-20 16:36:51 -07001296void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001297 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001298 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001299
Mike Reedc42a1cd2017-02-14 14:25:14 -05001300 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001301}
1302
1303void SkCanvas::setMatrix(const SkMatrix& matrix) {
1304 this->checkForDeferredSave();
1305 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001306 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001307}
1308
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001310 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311}
1312
1313//////////////////////////////////////////////////////////////////////////////
1314
Mike Reedc1f77742016-12-09 09:00:50 -05001315void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001316 if (!rect.isFinite()) {
1317 return;
1318 }
reed2ff1fce2014-12-11 07:07:37 -08001319 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001320 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1321 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001322}
1323
Mike Reedc1f77742016-12-09 09:00:50 -05001324void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001325 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001326
Mike Reed7627fa52017-02-08 10:07:53 -05001327 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001328
reedc64eff52015-11-21 12:39:45 -08001329 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001330 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1331 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001332 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333}
1334
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001335void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1336 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001337 if (fClipRestrictionRect.isEmpty()) {
1338 // we notify the device, but we *dont* resolve deferred saves (since we're just
1339 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001340 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001341 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001342 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001343 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001344 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001345 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001346 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1347 }
1348}
1349
Mike Reedc1f77742016-12-09 09:00:50 -05001350void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001351 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001352 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001353 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001354 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1355 } else {
1356 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001357 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001358}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001359
Mike Reedc1f77742016-12-09 09:00:50 -05001360void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001361 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001362
Brian Salomona3b45d42016-10-03 11:36:16 -04001363 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001364
Mike Reed7627fa52017-02-08 10:07:53 -05001365 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001366
Mike Reed20800c82017-11-15 16:09:04 -05001367 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1368 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001369 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001370}
1371
Mike Reedc1f77742016-12-09 09:00:50 -05001372void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001373 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001374 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001375
1376 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1377 SkRect r;
1378 if (path.isRect(&r)) {
1379 this->onClipRect(r, op, edgeStyle);
1380 return;
1381 }
1382 SkRRect rrect;
1383 if (path.isOval(&r)) {
1384 rrect.setOval(r);
1385 this->onClipRRect(rrect, op, edgeStyle);
1386 return;
1387 }
1388 if (path.isRRect(&rrect)) {
1389 this->onClipRRect(rrect, op, edgeStyle);
1390 return;
1391 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001392 }
robertphillips39f05382015-11-24 09:30:12 -08001393
1394 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001395}
1396
Mike Reedc1f77742016-12-09 09:00:50 -05001397void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001398 AutoValidateClip avc(this);
1399
Brian Salomona3b45d42016-10-03 11:36:16 -04001400 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001401
Mike Reed7627fa52017-02-08 10:07:53 -05001402 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001403
Brian Salomona3b45d42016-10-03 11:36:16 -04001404 const SkPath* rasterClipPath = &path;
1405 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001406 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1407 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001408 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409}
1410
Mike Reedc1f77742016-12-09 09:00:50 -05001411void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001412 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001413 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001414}
1415
Mike Reedc1f77742016-12-09 09:00:50 -05001416void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001417 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001418
reed@google.com5c3d1472011-02-22 19:12:23 +00001419 AutoValidateClip avc(this);
1420
Mike Reed20800c82017-11-15 16:09:04 -05001421 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001422 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423}
1424
reed@google.com819c9212011-02-23 18:56:55 +00001425#ifdef SK_DEBUG
1426void SkCanvas::validateClip() const {
1427 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001428 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001429 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001430 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001431 return;
1432 }
reed@google.com819c9212011-02-23 18:56:55 +00001433}
1434#endif
1435
Mike Reeda1361362017-03-07 09:37:29 -05001436bool SkCanvas::androidFramework_isClipAA() const {
1437 bool containsAA = false;
1438
1439 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1440
1441 return containsAA;
1442}
1443
1444class RgnAccumulator {
1445 SkRegion* fRgn;
1446public:
1447 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1448 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1449 SkIPoint origin = device->getOrigin();
1450 if (origin.x() | origin.y()) {
1451 rgn->translate(origin.x(), origin.y());
1452 }
1453 fRgn->op(*rgn, SkRegion::kUnion_Op);
1454 }
1455};
1456
1457void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1458 RgnAccumulator accum(rgn);
1459 SkRegion tmp;
1460
1461 rgn->setEmpty();
1462 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001463}
1464
reed@google.com5c3d1472011-02-22 19:12:23 +00001465///////////////////////////////////////////////////////////////////////////////
1466
reed@google.com754de5f2014-02-24 19:38:20 +00001467bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001468 return fMCRec->fRasterClip.isEmpty();
1469
1470 // TODO: should we only use the conservative answer in a recording canvas?
1471#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001472 SkBaseDevice* dev = this->getTopDevice();
1473 // if no device we return true
1474 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001475#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001476}
1477
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001478bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001479 SkBaseDevice* dev = this->getTopDevice();
1480 // if no device we return false
1481 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001482}
1483
msarettfbfa2582016-08-12 08:29:08 -07001484static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1485#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1486 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1487 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1488 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1489 return 0xF != _mm_movemask_ps(mask);
1490#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1491 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1492 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1493 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1494 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1495#else
1496 SkRect devRectAsRect;
1497 SkRect devClipAsRect;
1498 devRect.store(&devRectAsRect.fLeft);
1499 devClip.store(&devClipAsRect.fLeft);
1500 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1501#endif
1502}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001503
msarettfbfa2582016-08-12 08:29:08 -07001504// It's important for this function to not be inlined. Otherwise the compiler will share code
1505// between the fast path and the slow path, resulting in two slow paths.
1506static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1507 const SkMatrix& matrix) {
1508 SkRect deviceRect;
1509 matrix.mapRect(&deviceRect, src);
1510 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1511}
1512
1513bool SkCanvas::quickReject(const SkRect& src) const {
1514#ifdef SK_DEBUG
1515 // Verify that fDeviceClipBounds are set properly.
1516 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001517 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001518 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001519 } else {
msarettfbfa2582016-08-12 08:29:08 -07001520 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001521 }
msarettfbfa2582016-08-12 08:29:08 -07001522
msarett9637ea92016-08-18 14:03:30 -07001523 // Verify that fIsScaleTranslate is set properly.
1524 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001525#endif
1526
msarett9637ea92016-08-18 14:03:30 -07001527 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001528 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1529 }
1530
1531 // We inline the implementation of mapScaleTranslate() for the fast path.
1532 float sx = fMCRec->fMatrix.getScaleX();
1533 float sy = fMCRec->fMatrix.getScaleY();
1534 float tx = fMCRec->fMatrix.getTranslateX();
1535 float ty = fMCRec->fMatrix.getTranslateY();
1536 Sk4f scale(sx, sy, sx, sy);
1537 Sk4f trans(tx, ty, tx, ty);
1538
1539 // Apply matrix.
1540 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1541
1542 // Make sure left < right, top < bottom.
1543 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1544 Sk4f min = Sk4f::Min(ltrb, rblt);
1545 Sk4f max = Sk4f::Max(ltrb, rblt);
1546 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1547 // ARM this sequence generates the fastest (a single instruction).
1548 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1549
1550 // Check if the device rect is NaN or outside the clip.
1551 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001552}
1553
reed@google.com3b3e8952012-08-16 20:53:31 +00001554bool SkCanvas::quickReject(const SkPath& path) const {
1555 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001556}
1557
Mike Klein83c8dd92017-11-28 17:08:45 -05001558SkRect SkCanvas::getLocalClipBounds() const {
1559 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001560 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001561 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001562 }
1563
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001564 SkMatrix inverse;
1565 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001566 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001567 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001568 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001569
Mike Reed42e8c532017-01-23 14:09:13 -05001570 SkRect bounds;
Mike Reed42e8c532017-01-23 14:09:13 -05001571 // adjust it outwards in case we are antialiasing
Mike Reedb57b9312018-04-23 12:12:54 -04001572 const int margin = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001573
Mike Reedb57b9312018-04-23 12:12:54 -04001574 SkRect r = SkRect::Make(ibounds.makeOutset(margin, margin));
Mike Reed42e8c532017-01-23 14:09:13 -05001575 inverse.mapRect(&bounds, r);
1576 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001577}
1578
Mike Klein83c8dd92017-11-28 17:08:45 -05001579SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001580 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001581}
1582
reed@android.com8a1c16f2008-12-17 15:59:43 +00001583const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001584 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001585}
1586
Brian Osman11052242016-10-27 14:47:55 -04001587GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001588 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001589 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001590}
1591
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001592GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001593 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001594 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001595}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001596
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001597void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1598 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001599 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001600 if (outer.isEmpty()) {
1601 return;
1602 }
1603 if (inner.isEmpty()) {
1604 this->drawRRect(outer, paint);
1605 return;
1606 }
1607
1608 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001609 // be able to return ...
1610 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001611 //
1612 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001613 if (!outer.getBounds().contains(inner.getBounds())) {
1614 return;
1615 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001616
1617 this->onDrawDRRect(outer, inner, paint);
1618}
1619
reed41af9662015-01-05 07:49:08 -08001620void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001621 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001622 this->onDrawPaint(paint);
1623}
1624
1625void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001626 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001627 // To avoid redundant logic in our culling code and various backends, we always sort rects
1628 // before passing them along.
1629 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001630}
1631
msarettdca352e2016-08-26 06:37:45 -07001632void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001633 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001634 if (region.isEmpty()) {
1635 return;
1636 }
1637
1638 if (region.isRect()) {
1639 return this->drawIRect(region.getBounds(), paint);
1640 }
1641
1642 this->onDrawRegion(region, paint);
1643}
1644
reed41af9662015-01-05 07:49:08 -08001645void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001646 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001647 // To avoid redundant logic in our culling code and various backends, we always sort rects
1648 // before passing them along.
1649 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001650}
1651
1652void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001653 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001654 this->onDrawRRect(rrect, paint);
1655}
1656
1657void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001658 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001659 this->onDrawPoints(mode, count, pts, paint);
1660}
1661
Mike Reede88a1cb2017-03-17 09:50:46 -04001662void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1663 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001664 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001665 RETURN_ON_NULL(vertices);
Brian Salomoncccafe82018-04-28 16:13:08 -04001666 // We expect fans to be converted to triangles when building or deserializing SkVertices.
1667 SkASSERT(vertices->mode() != SkVertices::kTriangleFan_VertexMode);
Ruiqi Maof5101492018-06-29 14:32:21 -04001668 this->onDrawVerticesObject(vertices.get(), nullptr, 0, mode, paint);
Mike Reede88a1cb2017-03-17 09:50:46 -04001669}
1670
1671void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001672 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001673 RETURN_ON_NULL(vertices);
Ruiqi Maof5101492018-06-29 14:32:21 -04001674 this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
1675}
1676
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001677void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
1678 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001679 TRACE_EVENT0("skia", TRACE_FUNC);
1680 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001681 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001682 this->onDrawVerticesObject(vertices.get(), bones, boneCount, mode, paint);
1683}
1684
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001685void SkCanvas::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
1686 int boneCount, SkBlendMode mode, const SkPaint& paint) {
Ruiqi Maof5101492018-06-29 14:32:21 -04001687 TRACE_EVENT0("skia", TRACE_FUNC);
1688 RETURN_ON_NULL(vertices);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001689 SkASSERT(boneCount <= 80);
Ruiqi Maof5101492018-06-29 14:32:21 -04001690 this->onDrawVerticesObject(vertices, bones, boneCount, mode, paint);
reed41af9662015-01-05 07:49:08 -08001691}
1692
1693void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001694 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001695 this->onDrawPath(path, paint);
1696}
1697
reeda85d4d02015-05-06 12:56:48 -07001698void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001699 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001700 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001701 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001702}
1703
Mike Reedc4e31092018-01-30 11:15:27 -05001704// Returns true if the rect can be "filled" : non-empty and finite
1705static bool fillable(const SkRect& r) {
1706 SkScalar w = r.width();
1707 SkScalar h = r.height();
1708 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1709}
1710
reede47829b2015-08-06 10:02:53 -07001711void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1712 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001713 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001714 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001715 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001716 return;
1717 }
1718 this->onDrawImageRect(image, &src, dst, paint, constraint);
1719}
reed41af9662015-01-05 07:49:08 -08001720
reed84984ef2015-07-17 07:09:43 -07001721void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1722 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001723 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001724 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001725}
1726
reede47829b2015-08-06 10:02:53 -07001727void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1728 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001729 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001730 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1731 constraint);
1732}
reede47829b2015-08-06 10:02:53 -07001733
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001734namespace {
Brian Salomon969be1c2018-05-21 14:37:49 -04001735class LatticePaint : SkNoncopyable {
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001736public:
Brian Salomon969be1c2018-05-21 14:37:49 -04001737 LatticePaint(const SkPaint* origPaint) : fPaint(origPaint) {
1738 if (!origPaint) {
1739 return;
1740 }
1741 if (origPaint->getFilterQuality() > kLow_SkFilterQuality) {
1742 fPaint.writable()->setFilterQuality(kLow_SkFilterQuality);
1743 }
1744 if (origPaint->getMaskFilter()) {
1745 fPaint.writable()->setMaskFilter(nullptr);
1746 }
1747 if (origPaint->isAntiAlias()) {
1748 fPaint.writable()->setAntiAlias(false);
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001749 }
1750 }
1751
1752 const SkPaint* get() const {
1753 return fPaint;
1754 }
1755
1756private:
Brian Salomon969be1c2018-05-21 14:37:49 -04001757 SkTCopyOnFirstWrite<SkPaint> fPaint;
Leon Scroggins III57e1f022018-04-20 14:53:00 -04001758};
1759} // namespace
1760
reed4c21dc52015-06-25 12:32:03 -07001761void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1762 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001763 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001764 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001765 if (dst.isEmpty()) {
1766 return;
1767 }
msarett552bca92016-08-03 06:53:26 -07001768 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001769 LatticePaint latticePaint(paint);
1770 this->onDrawImageNine(image, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001771 } else {
reede47829b2015-08-06 10:02:53 -07001772 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001773 }
reed4c21dc52015-06-25 12:32:03 -07001774}
1775
msarett16882062016-08-16 09:31:08 -07001776void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1777 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001778 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001779 RETURN_ON_NULL(image);
1780 if (dst.isEmpty()) {
1781 return;
1782 }
msarett71df2d72016-09-30 12:41:42 -07001783
1784 SkIRect bounds;
1785 Lattice latticePlusBounds = lattice;
1786 if (!latticePlusBounds.fBounds) {
1787 bounds = SkIRect::MakeWH(image->width(), image->height());
1788 latticePlusBounds.fBounds = &bounds;
1789 }
1790
1791 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001792 LatticePaint latticePaint(paint);
1793 this->onDrawImageLattice(image, latticePlusBounds, dst, latticePaint.get());
msarett16882062016-08-16 09:31:08 -07001794 } else {
1795 this->drawImageRect(image, dst, paint);
1796 }
1797}
1798
reed41af9662015-01-05 07:49:08 -08001799void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001800 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001801 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001802 return;
1803 }
reed41af9662015-01-05 07:49:08 -08001804 this->onDrawBitmap(bitmap, dx, dy, paint);
1805}
1806
reede47829b2015-08-06 10:02:53 -07001807void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001808 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001809 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001810 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001811 return;
1812 }
reede47829b2015-08-06 10:02:53 -07001813 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001814}
1815
reed84984ef2015-07-17 07:09:43 -07001816void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1817 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001818 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001819}
1820
reede47829b2015-08-06 10:02:53 -07001821void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1822 SrcRectConstraint constraint) {
1823 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1824 constraint);
1825}
reede47829b2015-08-06 10:02:53 -07001826
reed41af9662015-01-05 07:49:08 -08001827void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1828 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001829 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001830 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001831 return;
1832 }
msarett552bca92016-08-03 06:53:26 -07001833 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001834 LatticePaint latticePaint(paint);
1835 this->onDrawBitmapNine(bitmap, center, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001836 } else {
reeda5517e22015-07-14 10:54:12 -07001837 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001838 }
reed41af9662015-01-05 07:49:08 -08001839}
1840
msarettc573a402016-08-02 08:05:56 -07001841void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1842 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001843 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001844 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001845 return;
1846 }
msarett71df2d72016-09-30 12:41:42 -07001847
1848 SkIRect bounds;
1849 Lattice latticePlusBounds = lattice;
1850 if (!latticePlusBounds.fBounds) {
1851 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1852 latticePlusBounds.fBounds = &bounds;
1853 }
1854
1855 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
Brian Salomon969be1c2018-05-21 14:37:49 -04001856 LatticePaint latticePaint(paint);
1857 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, latticePaint.get());
msarett552bca92016-08-03 06:53:26 -07001858 } else {
msarett16882062016-08-16 09:31:08 -07001859 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001860 }
msarettc573a402016-08-02 08:05:56 -07001861}
1862
reed71c3c762015-06-24 10:29:17 -07001863void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001864 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001865 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001866 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001867 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001868 if (count <= 0) {
1869 return;
1870 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001871 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001872 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001873 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001874}
1875
reedf70b5312016-03-04 16:36:20 -08001876void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001877 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001878 if (key) {
1879 this->onDrawAnnotation(rect, key, value);
1880 }
1881}
1882
reede47829b2015-08-06 10:02:53 -07001883void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1884 const SkPaint* paint, SrcRectConstraint constraint) {
1885 if (src) {
1886 this->drawImageRect(image, *src, dst, paint, constraint);
1887 } else {
1888 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1889 dst, paint, constraint);
1890 }
1891}
1892void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1893 const SkPaint* paint, SrcRectConstraint constraint) {
1894 if (src) {
1895 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1896 } else {
1897 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1898 dst, paint, constraint);
1899 }
1900}
1901
Mike Reed4204da22017-05-17 08:53:36 -04001902void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001903 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001904 this->onDrawShadowRec(path, rec);
1905}
1906
1907void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1908 SkPaint paint;
1909 const SkRect& pathBounds = path.getBounds();
1910
Ben Wagner2c312c42018-06-27 14:46:46 -04001911 LOOPER_BEGIN(paint, &pathBounds)
Mike Reed4204da22017-05-17 08:53:36 -04001912 while (iter.next()) {
1913 iter.fDevice->drawShadow(path, rec);
1914 }
1915 LOOPER_END
1916}
1917
reed@android.com8a1c16f2008-12-17 15:59:43 +00001918//////////////////////////////////////////////////////////////////////////////
1919// These are the virtual drawing methods
1920//////////////////////////////////////////////////////////////////////////////
1921
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001922void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001923 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001924 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1925 }
1926}
1927
reed41af9662015-01-05 07:49:08 -08001928void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001929 this->internalDrawPaint(paint);
1930}
1931
1932void SkCanvas::internalDrawPaint(const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04001933 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001934
1935 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001936 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001937 }
1938
reed@google.com4e2b3d32011-04-07 14:18:59 +00001939 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001940}
1941
reed41af9662015-01-05 07:49:08 -08001942void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1943 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001944 if ((long)count <= 0) {
1945 return;
1946 }
1947
Mike Reed822128b2017-02-28 16:41:03 -05001948 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001949 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001950 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001951 // special-case 2 points (common for drawing a single line)
1952 if (2 == count) {
1953 r.set(pts[0], pts[1]);
1954 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001955 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001956 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001957 if (!r.isFinite()) {
1958 return;
1959 }
Mike Reed822128b2017-02-28 16:41:03 -05001960 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001961 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1962 return;
1963 }
1964 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001965 }
reed@google.coma584aed2012-05-16 14:06:02 +00001966
halcanary96fcdcc2015-08-27 07:41:13 -07001967 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001968
Ben Wagner2c312c42018-06-27 14:46:46 -04001969 LOOPER_BEGIN(paint, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001970
reed@android.com8a1c16f2008-12-17 15:59:43 +00001971 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001972 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001973 }
reed@google.com4b226022011-01-11 18:32:13 +00001974
reed@google.com4e2b3d32011-04-07 14:18:59 +00001975 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001976}
1977
reed4a167172016-08-18 17:15:25 -07001978static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1979 return ((intptr_t)paint.getImageFilter() |
reed4a167172016-08-18 17:15:25 -07001980 (intptr_t)paint.getLooper() ) != 0;
1981}
1982
reed41af9662015-01-05 07:49:08 -08001983void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001984 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001985 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001986 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001987 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001988 return;
1989 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001990 }
reed@google.com4b226022011-01-11 18:32:13 +00001991
reed4a167172016-08-18 17:15:25 -07001992 if (needs_autodrawlooper(this, paint)) {
Ben Wagner2c312c42018-06-27 14:46:46 -04001993 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001994
reed4a167172016-08-18 17:15:25 -07001995 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001996 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07001997 }
1998
1999 LOOPER_END
Mike Reed49f8da02018-08-27 10:48:52 -04002000 } else if (!paint.nothingToDraw()) {
Mike Reed822128b2017-02-28 16:41:03 -05002001 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002002 SkDrawIter iter(this);
2003 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002004 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002005 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002006 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002007}
2008
msarett44df6512016-08-25 13:54:30 -07002009void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002010 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002011 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002012 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002013 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2014 return;
2015 }
msarett44df6512016-08-25 13:54:30 -07002016 }
2017
Ben Wagner2c312c42018-06-27 14:46:46 -04002018 LOOPER_BEGIN(paint, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002019
2020 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002021 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002022 }
2023
2024 LOOPER_END
2025}
2026
reed41af9662015-01-05 07:49:08 -08002027void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002028 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00002029 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002030 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04002031 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002032 return;
2033 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002034 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002035
Ben Wagner2c312c42018-06-27 14:46:46 -04002036 LOOPER_BEGIN(paint, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002037
2038 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002039 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002040 }
2041
2042 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002043}
2044
bsalomonac3aa242016-08-19 11:25:19 -07002045void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2046 SkScalar sweepAngle, bool useCenter,
2047 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002048 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002049 if (paint.canComputeFastBounds()) {
2050 SkRect storage;
2051 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002052 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002053 return;
2054 }
bsalomonac3aa242016-08-19 11:25:19 -07002055 }
2056
Ben Wagner2c312c42018-06-27 14:46:46 -04002057 LOOPER_BEGIN(paint, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002058
2059 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002060 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002061 }
2062
2063 LOOPER_END
2064}
2065
reed41af9662015-01-05 07:49:08 -08002066void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002067 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002068 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002069 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2070 return;
2071 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002072 }
2073
2074 if (rrect.isRect()) {
2075 // call the non-virtual version
2076 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002077 return;
2078 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002079 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002080 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2081 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002082 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002083
Ben Wagner2c312c42018-06-27 14:46:46 -04002084 LOOPER_BEGIN(paint, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002085
2086 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002087 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002088 }
2089
2090 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002091}
2092
Mike Reed822128b2017-02-28 16:41:03 -05002093void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002094 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002095 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002096 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2097 return;
2098 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002099 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002100
Ben Wagner2c312c42018-06-27 14:46:46 -04002101 LOOPER_BEGIN(paint, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002102
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002103 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002104 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002105 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002106
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002107 LOOPER_END
2108}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002109
reed41af9662015-01-05 07:49:08 -08002110void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002111 if (!path.isFinite()) {
2112 return;
2113 }
2114
Mike Reed822128b2017-02-28 16:41:03 -05002115 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002116 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002117 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002118 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2119 return;
2120 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002121 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002122
Mike Reed822128b2017-02-28 16:41:03 -05002123 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002124 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002125 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002126 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002127 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002128 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002129
Ben Wagner2c312c42018-06-27 14:46:46 -04002130 LOOPER_BEGIN(paint, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002131
2132 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002133 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002134 }
2135
reed@google.com4e2b3d32011-04-07 14:18:59 +00002136 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002137}
2138
reed262a71b2015-12-05 13:07:27 -08002139bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002140 if (!paint.getImageFilter()) {
2141 return false;
2142 }
2143
2144 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002145 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002146 return false;
2147 }
2148
2149 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2150 // Once we can filter and the filter will return a result larger than itself, we should be
2151 // able to remove this constraint.
2152 // skbug.com/4526
2153 //
2154 SkPoint pt;
2155 ctm.mapXY(x, y, &pt);
2156 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2157 return ir.contains(fMCRec->fRasterClip.getBounds());
2158}
2159
Mike Reedf441cfc2018-04-11 14:50:16 -04002160// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
2161// given the drawing semantics for drawImage/bitmap (skbug.com/7804) and return it, or the original
2162// null.
2163static const SkPaint* init_image_paint(SkPaint* real, const SkPaint* paintParam) {
2164 if (paintParam) {
2165 *real = *paintParam;
2166 real->setStyle(SkPaint::kFill_Style);
2167 real->setPathEffect(nullptr);
2168 paintParam = real;
2169 }
2170 return paintParam;
2171}
2172
reeda85d4d02015-05-06 12:56:48 -07002173void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002174 SkPaint realPaint;
2175 paint = init_image_paint(&realPaint, paint);
2176
reeda85d4d02015-05-06 12:56:48 -07002177 SkRect bounds = SkRect::MakeXYWH(x, y,
2178 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002179 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002180 SkRect tmp = bounds;
2181 if (paint) {
2182 paint->computeFastBounds(tmp, &tmp);
2183 }
2184 if (this->quickReject(tmp)) {
2185 return;
2186 }
reeda85d4d02015-05-06 12:56:48 -07002187 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002188 // At this point we need a real paint object. If the caller passed null, then we should
2189 // use realPaint (in its default state). If the caller did pass a paint, then we have copied
2190 // (and modified) it in realPaint. Thus either way, "realPaint" is what we want to use.
2191 paint = &realPaint;
reed262a71b2015-12-05 13:07:27 -08002192
reeda2217ef2016-07-20 06:04:34 -07002193 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002194 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2195 *paint);
2196 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002197 special = this->getDevice()->makeSpecial(image);
2198 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002199 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002200 }
2201 }
2202
reed262a71b2015-12-05 13:07:27 -08002203 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2204
reeda85d4d02015-05-06 12:56:48 -07002205 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002206 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002207 if (special) {
2208 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002209 iter.fDevice->ctm().mapXY(x, y, &pt);
2210 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002211 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002212 SkScalarRoundToInt(pt.fY), pnt,
2213 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002214 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002215 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002216 }
reeda85d4d02015-05-06 12:56:48 -07002217 }
halcanary9d524f22016-03-29 09:03:52 -07002218
reeda85d4d02015-05-06 12:56:48 -07002219 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002220}
2221
reed41af9662015-01-05 07:49:08 -08002222void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002223 const SkPaint* paint, SrcRectConstraint constraint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002224 SkPaint realPaint;
2225 paint = init_image_paint(&realPaint, paint);
2226
halcanary96fcdcc2015-08-27 07:41:13 -07002227 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002228 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002229 if (paint) {
2230 paint->computeFastBounds(dst, &storage);
2231 }
2232 if (this->quickReject(storage)) {
2233 return;
2234 }
reeda85d4d02015-05-06 12:56:48 -07002235 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002236 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002237
Ben Wagner2c312c42018-06-27 14:46:46 -04002238 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002239
reeda85d4d02015-05-06 12:56:48 -07002240 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002241 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002242 }
halcanary9d524f22016-03-29 09:03:52 -07002243
reeda85d4d02015-05-06 12:56:48 -07002244 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002245}
2246
reed41af9662015-01-05 07:49:08 -08002247void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002248 SkDEBUGCODE(bitmap.validate();)
2249
reed33366972015-10-08 09:22:02 -07002250 if (bitmap.drawsNothing()) {
2251 return;
2252 }
2253
Mike Reedf441cfc2018-04-11 14:50:16 -04002254 SkPaint realPaint;
2255 init_image_paint(&realPaint, paint);
2256 paint = &realPaint;
reed33366972015-10-08 09:22:02 -07002257
Mike Reed822128b2017-02-28 16:41:03 -05002258 SkRect bounds;
2259 bitmap.getBounds(&bounds);
2260 bounds.offset(x, y);
2261 bool canFastBounds = paint->canComputeFastBounds();
2262 if (canFastBounds) {
2263 SkRect storage;
2264 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002265 return;
2266 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002267 }
reed@google.com4b226022011-01-11 18:32:13 +00002268
reeda2217ef2016-07-20 06:04:34 -07002269 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002270 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2271 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002272 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002273 special = this->getDevice()->makeSpecial(bitmap);
2274 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002275 drawAsSprite = false;
2276 }
2277 }
2278
Mike Reed822128b2017-02-28 16:41:03 -05002279 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002280
2281 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002282 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002283 if (special) {
reed262a71b2015-12-05 13:07:27 -08002284 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002285 iter.fDevice->ctm().mapXY(x, y, &pt);
2286 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002287 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002288 SkScalarRoundToInt(pt.fY), pnt,
2289 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002290 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002291 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002292 }
reed33366972015-10-08 09:22:02 -07002293 }
msarettfbfa2582016-08-12 08:29:08 -07002294
reed33366972015-10-08 09:22:02 -07002295 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002296}
2297
reed@google.com9987ec32011-09-07 11:57:52 +00002298// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002299void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002300 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002301 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002302 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002303 return;
2304 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002305
halcanary96fcdcc2015-08-27 07:41:13 -07002306 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002307 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002308 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2309 return;
2310 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002311 }
reed@google.com3d608122011-11-21 15:16:16 +00002312
reed@google.com33535f32012-09-25 15:37:50 +00002313 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002314 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002315 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002316 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002317
Ben Wagner2c312c42018-06-27 14:46:46 -04002318 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, &dst, bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002319
reed@google.com33535f32012-09-25 15:37:50 +00002320 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002321 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002322 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002323
reed@google.com33535f32012-09-25 15:37:50 +00002324 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002325}
2326
reed41af9662015-01-05 07:49:08 -08002327void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002328 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002329 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002330 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002331}
2332
reed4c21dc52015-06-25 12:32:03 -07002333void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2334 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002335 SkPaint realPaint;
2336 paint = init_image_paint(&realPaint, paint);
2337
halcanary96fcdcc2015-08-27 07:41:13 -07002338 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002339 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002340 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2341 return;
2342 }
reed@google.com3d608122011-11-21 15:16:16 +00002343 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002344 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002345
Ben Wagner2c312c42018-06-27 14:46:46 -04002346 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002347
reed4c21dc52015-06-25 12:32:03 -07002348 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002349 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002350 }
halcanary9d524f22016-03-29 09:03:52 -07002351
reed4c21dc52015-06-25 12:32:03 -07002352 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002353}
2354
reed41af9662015-01-05 07:49:08 -08002355void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2356 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002357 SkDEBUGCODE(bitmap.validate();)
Mike Reedf441cfc2018-04-11 14:50:16 -04002358 SkPaint realPaint;
2359 paint = init_image_paint(&realPaint, paint);
reed@google.com9987ec32011-09-07 11:57:52 +00002360
halcanary96fcdcc2015-08-27 07:41:13 -07002361 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002362 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002363 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2364 return;
2365 }
reed4c21dc52015-06-25 12:32:03 -07002366 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002367 paint = &realPaint;
halcanary9d524f22016-03-29 09:03:52 -07002368
Ben Wagner2c312c42018-06-27 14:46:46 -04002369 LOOPER_BEGIN(*paint, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002370
reed4c21dc52015-06-25 12:32:03 -07002371 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002372 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002373 }
halcanary9d524f22016-03-29 09:03:52 -07002374
reed4c21dc52015-06-25 12:32:03 -07002375 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002376}
2377
msarett16882062016-08-16 09:31:08 -07002378void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2379 const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002380 SkPaint realPaint;
2381 paint = init_image_paint(&realPaint, paint);
2382
msarett16882062016-08-16 09:31:08 -07002383 if (nullptr == paint || paint->canComputeFastBounds()) {
2384 SkRect storage;
2385 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2386 return;
2387 }
2388 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002389 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002390
Ben Wagner2c312c42018-06-27 14:46:46 -04002391 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002392
2393 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002394 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002395 }
2396
2397 LOOPER_END
2398}
2399
2400void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2401 const SkRect& dst, const SkPaint* paint) {
Mike Reedf441cfc2018-04-11 14:50:16 -04002402 SkPaint realPaint;
2403 paint = init_image_paint(&realPaint, paint);
2404
msarett16882062016-08-16 09:31:08 -07002405 if (nullptr == paint || paint->canComputeFastBounds()) {
2406 SkRect storage;
2407 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2408 return;
2409 }
2410 }
Mike Reedf441cfc2018-04-11 14:50:16 -04002411 paint = &realPaint;
msarett16882062016-08-16 09:31:08 -07002412
Ben Wagner2c312c42018-06-27 14:46:46 -04002413 LOOPER_BEGIN(*paint, &dst)
msarett16882062016-08-16 09:31:08 -07002414
2415 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002416 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002417 }
2418
2419 LOOPER_END
2420}
2421
reed@google.come0d9ce82014-04-23 04:00:17 +00002422void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2423 const SkPaint& paint) {
Herb Derby41f4f312018-06-06 17:45:53 +00002424
Ben Wagner2c312c42018-06-27 14:46:46 -04002425 LOOPER_BEGIN(paint, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002426
2427 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002428 fScratchGlyphRunBuilder->drawText(
Herb Derby4a447432018-06-22 11:45:27 -04002429 looper.paint(), text, byteLength, SkPoint::Make(x, y));
Herb Derby8a6348e2018-07-12 15:30:35 -04002430 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002431 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002432 }
2433
reed@google.com4e2b3d32011-04-07 14:18:59 +00002434 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002435}
2436
reed@google.come0d9ce82014-04-23 04:00:17 +00002437void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2438 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002439
Ben Wagner2c312c42018-06-27 14:46:46 -04002440 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002441
reed@android.com8a1c16f2008-12-17 15:59:43 +00002442 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002443 fScratchGlyphRunBuilder->drawPosText(looper.paint(), text, byteLength, pos);
Herb Derby8a6348e2018-07-12 15:30:35 -04002444 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002445 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002446 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002447
reed@google.com4e2b3d32011-04-07 14:18:59 +00002448 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002449}
2450
reed@google.come0d9ce82014-04-23 04:00:17 +00002451void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2452 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002453
Ben Wagner2c312c42018-06-27 14:46:46 -04002454 LOOPER_BEGIN(paint, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002455
reed@android.com8a1c16f2008-12-17 15:59:43 +00002456 while (iter.next()) {
Herb Derbyc434ade2018-07-11 16:07:01 -04002457 fScratchGlyphRunBuilder->drawPosTextH(
Herb Derby4a447432018-06-22 11:45:27 -04002458 looper.paint(), text, byteLength, xpos, constY);
Herb Derby8a6348e2018-07-12 15:30:35 -04002459 auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb983e6b2018-07-13 13:26:29 -04002460 iter.fDevice->drawGlyphRunList(glyphRunList);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002461 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002462
reed@google.com4e2b3d32011-04-07 14:18:59 +00002463 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002464}
2465
Herb Derby2eacff02018-07-18 13:41:15 -04002466void SkCanvas::onDrawTextRSXform(const void* text, size_t len, const SkRSXform xform[],
reed45561a02016-07-07 12:47:17 -07002467 const SkRect* cullRect, const SkPaint& paint) {
2468 if (cullRect && this->quickReject(*cullRect)) {
2469 return;
2470 }
2471
Ben Wagner2c312c42018-06-27 14:46:46 -04002472 LOOPER_BEGIN(paint, nullptr)
reed45561a02016-07-07 12:47:17 -07002473
2474 while (iter.next()) {
Herb Derby2eacff02018-07-18 13:41:15 -04002475 fScratchGlyphRunBuilder->drawTextAtOrigin(paint, text, len);
2476 auto list = fScratchGlyphRunBuilder->useGlyphRunList();
Herb Derbyb935cf82018-07-26 16:54:18 -04002477 if (!list.empty()) {
2478 auto glyphRun = list[0];
Herb Derby2eacff02018-07-18 13:41:15 -04002479 iter.fDevice->drawGlyphRunRSXform(&glyphRun, xform);
2480 }
reed45561a02016-07-07 12:47:17 -07002481 }
2482
2483 LOOPER_END
2484}
2485
fmalita00d5c2c2014-08-21 08:53:26 -07002486void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2487 const SkPaint& paint) {
fmalita85d5eb92015-03-04 11:20:12 -08002488 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002489 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002490 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002491 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002492 SkRect tmp;
2493 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2494 return;
2495 }
2496 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002497 }
2498
fmalita024f9962015-03-03 19:08:17 -08002499 // We cannot filter in the looper as we normally do, because the paint is
2500 // incomplete at this point (text-related attributes are embedded within blob run paints).
Ben Wagner2c312c42018-06-27 14:46:46 -04002501 LOOPER_BEGIN(paint, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002502
fmalitaaa1b9122014-08-28 14:32:24 -07002503 while (iter.next()) {
Herb Derbyb983e6b2018-07-13 13:26:29 -04002504 fScratchGlyphRunBuilder->drawTextBlob(looper.paint(), *blob, SkPoint::Make(x, y));
2505 iter.fDevice->drawGlyphRunList(fScratchGlyphRunBuilder->useGlyphRunList());
fmalita00d5c2c2014-08-21 08:53:26 -07002506 }
2507
fmalitaaa1b9122014-08-28 14:32:24 -07002508 LOOPER_END
fmalita00d5c2c2014-08-21 08:53:26 -07002509}
2510
Cary Clark2a475ea2017-04-28 15:35:12 -04002511void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2512 this->drawText(string.c_str(), string.size(), x, y, paint);
2513}
2514
reed@google.come0d9ce82014-04-23 04:00:17 +00002515// These will become non-virtual, so they always call the (virtual) onDraw... method
2516void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2517 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002518 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002519 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002520 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002521 this->onDrawText(text, byteLength, x, y, paint);
2522 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002523}
2524void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2525 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002526 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002527 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002528 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002529 this->onDrawPosText(text, byteLength, pos, paint);
2530 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002531}
2532void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2533 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002534 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002535 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002536 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002537 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2538 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002539}
Mike Reed7c8d2e92018-08-27 16:38:05 -04002540
reed45561a02016-07-07 12:47:17 -07002541void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2542 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002543 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002544 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002545 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002546 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2547 }
2548}
fmalita00d5c2c2014-08-21 08:53:26 -07002549void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2550 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002551 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002552 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002553 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002554 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002555}
reed@google.come0d9ce82014-04-23 04:00:17 +00002556
Ruiqi Maoc97a3392018-08-15 10:44:19 -04002557void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
Ruiqi Maof5101492018-06-29 14:32:21 -04002558 int boneCount, SkBlendMode bmode, const SkPaint& paint) {
Ben Wagner2c312c42018-06-27 14:46:46 -04002559 LOOPER_BEGIN(paint, nullptr)
Brian Salomon199fb872017-02-06 09:41:10 -05002560
2561 while (iter.next()) {
2562 // In the common case of one iteration we could std::move vertices here.
Ruiqi Maof5101492018-06-29 14:32:21 -04002563 iter.fDevice->drawVertices(vertices, bones, boneCount, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002564 }
2565
2566 LOOPER_END
2567}
2568
dandovb3c9d1c2014-08-12 08:34:29 -07002569void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002570 const SkPoint texCoords[4], SkBlendMode bmode,
2571 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002572 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002573 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002574 return;
2575 }
mtklein6cfa73a2014-08-13 13:33:49 -07002576
Mike Reedfaba3712016-11-03 14:45:31 -04002577 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002578}
2579
2580void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002581 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002582 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002583 // Since a patch is always within the convex hull of the control points, we discard it when its
2584 // bounding rectangle is completely outside the current clip.
2585 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002586 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002587 if (this->quickReject(bounds)) {
2588 return;
2589 }
mtklein6cfa73a2014-08-13 13:33:49 -07002590
Ben Wagner2c312c42018-06-27 14:46:46 -04002591 LOOPER_BEGIN(paint, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002592
dandovecfff212014-08-04 10:02:00 -07002593 while (iter.next()) {
Brian Osmane0a99622018-07-09 16:12:27 -04002594 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002595 }
mtklein6cfa73a2014-08-13 13:33:49 -07002596
dandovecfff212014-08-04 10:02:00 -07002597 LOOPER_END
2598}
2599
reeda8db7282015-07-07 10:22:31 -07002600void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002601#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002602 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002603#endif
reede3b38ce2016-01-08 09:18:44 -08002604 RETURN_ON_NULL(dr);
2605 if (x || y) {
2606 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2607 this->onDrawDrawable(dr, &matrix);
2608 } else {
2609 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002610 }
2611}
2612
reeda8db7282015-07-07 10:22:31 -07002613void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002614#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002615 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002616#endif
reede3b38ce2016-01-08 09:18:44 -08002617 RETURN_ON_NULL(dr);
2618 if (matrix && matrix->isIdentity()) {
2619 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002620 }
reede3b38ce2016-01-08 09:18:44 -08002621 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002622}
2623
2624void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002625 // drawable bounds are no longer reliable (e.g. android displaylist)
2626 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002627 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002628}
2629
reed71c3c762015-06-24 10:29:17 -07002630void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002631 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002632 const SkRect* cull, const SkPaint* paint) {
2633 if (cull && this->quickReject(*cull)) {
2634 return;
2635 }
2636
2637 SkPaint pnt;
2638 if (paint) {
2639 pnt = *paint;
2640 }
halcanary9d524f22016-03-29 09:03:52 -07002641
Ben Wagner2c312c42018-06-27 14:46:46 -04002642 LOOPER_BEGIN(pnt, nullptr)
reed71c3c762015-06-24 10:29:17 -07002643 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002644 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002645 }
2646 LOOPER_END
2647}
2648
reedf70b5312016-03-04 16:36:20 -08002649void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2650 SkASSERT(key);
2651
2652 SkPaint paint;
Ben Wagner2c312c42018-06-27 14:46:46 -04002653 LOOPER_BEGIN(paint, nullptr)
reedf70b5312016-03-04 16:36:20 -08002654 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002655 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002656 }
2657 LOOPER_END
2658}
2659
reed@android.com8a1c16f2008-12-17 15:59:43 +00002660//////////////////////////////////////////////////////////////////////////////
2661// These methods are NOT virtual, and therefore must call back into virtual
2662// methods, rather than actually drawing themselves.
2663//////////////////////////////////////////////////////////////////////////////
2664
reed374772b2016-10-05 17:33:02 -07002665void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002666 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002667 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002668 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002669 this->drawPaint(paint);
2670}
2671
2672void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002673 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002674 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2675}
2676
Mike Reed3661bc92017-02-22 13:21:42 -05002677void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002678 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002679 pts[0].set(x0, y0);
2680 pts[1].set(x1, y1);
2681 this->drawPoints(kLines_PointMode, 2, pts, paint);
2682}
2683
Mike Reed3661bc92017-02-22 13:21:42 -05002684void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002685 if (radius < 0) {
2686 radius = 0;
2687 }
2688
2689 SkRect r;
2690 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002691 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002692}
2693
2694void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2695 const SkPaint& paint) {
2696 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002697 SkRRect rrect;
2698 rrect.setRectXY(r, rx, ry);
2699 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002700 } else {
2701 this->drawRect(r, paint);
2702 }
2703}
2704
reed@android.com8a1c16f2008-12-17 15:59:43 +00002705void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2706 SkScalar sweepAngle, bool useCenter,
2707 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002708 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002709 if (oval.isEmpty() || !sweepAngle) {
2710 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711 }
bsalomon21af9ca2016-08-25 12:29:23 -07002712 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002713}
2714
reed@android.comf76bacf2009-05-13 14:00:33 +00002715///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002716
Mike Klein88d90712018-01-27 17:30:04 +00002717/**
2718 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2719 * against the playback cost of recursing into the subpicture to get at its actual ops.
2720 *
2721 * For now we pick a conservatively small value, though measurement (and other heuristics like
2722 * the type of ops contained) may justify changing this value.
2723 */
2724#define kMaxPictureOpsToUnrollInsteadOfRef 1
2725
reedd5fa1a42014-08-09 11:08:05 -07002726void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002727 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002728 RETURN_ON_NULL(picture);
2729
reede3b38ce2016-01-08 09:18:44 -08002730 if (matrix && matrix->isIdentity()) {
2731 matrix = nullptr;
2732 }
Mike Klein88d90712018-01-27 17:30:04 +00002733 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2734 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2735 picture->playback(this);
2736 } else {
2737 this->onDrawPicture(picture, matrix, paint);
2738 }
reedd5fa1a42014-08-09 11:08:05 -07002739}
robertphillips9b14f262014-06-04 05:40:44 -07002740
reedd5fa1a42014-08-09 11:08:05 -07002741void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2742 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002743 if (!paint || paint->canComputeFastBounds()) {
2744 SkRect bounds = picture->cullRect();
2745 if (paint) {
2746 paint->computeFastBounds(bounds, &bounds);
2747 }
2748 if (matrix) {
2749 matrix->mapRect(&bounds);
2750 }
2751 if (this->quickReject(bounds)) {
2752 return;
2753 }
2754 }
2755
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002756 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002757 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002758}
2759
reed@android.com8a1c16f2008-12-17 15:59:43 +00002760///////////////////////////////////////////////////////////////////////////////
2761///////////////////////////////////////////////////////////////////////////////
2762
reed3aafe112016-08-18 12:45:34 -07002763SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002764 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002765
2766 SkASSERT(canvas);
2767
reed3aafe112016-08-18 12:45:34 -07002768 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769 fDone = !fImpl->next();
2770}
2771
2772SkCanvas::LayerIter::~LayerIter() {
2773 fImpl->~SkDrawIter();
2774}
2775
2776void SkCanvas::LayerIter::next() {
2777 fDone = !fImpl->next();
2778}
2779
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002780SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002781 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782}
2783
2784const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002785 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786}
2787
2788const SkPaint& SkCanvas::LayerIter::paint() const {
2789 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002790 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791 paint = &fDefaultPaint;
2792 }
2793 return *paint;
2794}
2795
Mike Reedca37f322018-03-08 13:22:16 -05002796SkIRect SkCanvas::LayerIter::clipBounds() const {
2797 return fImpl->fDevice->getGlobalBounds();
Mike Reeda1361362017-03-07 09:37:29 -05002798}
2799
reed@android.com8a1c16f2008-12-17 15:59:43 +00002800int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2801int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002802
2803///////////////////////////////////////////////////////////////////////////////
2804
Brian Osman10fc6fd2018-03-02 11:01:10 -05002805// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002806static bool supported_for_raster_canvas(const SkImageInfo& info) {
2807 switch (info.alphaType()) {
2808 case kPremul_SkAlphaType:
2809 case kOpaque_SkAlphaType:
2810 break;
2811 default:
2812 return false;
2813 }
2814
2815 switch (info.colorType()) {
2816 case kAlpha_8_SkColorType:
2817 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002818 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002819 case kRGBA_F16_SkColorType:
Mike Klein37854712018-06-26 11:43:06 -04002820 case kRGBA_F32_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002821 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002822 break;
2823 default:
2824 return false;
2825 }
2826
2827 return true;
2828}
2829
Mike Reed5df49342016-11-12 08:06:55 -06002830std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002831 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002832 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002833 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002834 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002835
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002836 SkBitmap bitmap;
2837 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002838 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002839 }
Mike Reed12f77342017-11-08 11:19:52 -05002840
2841 return props ?
2842 skstd::make_unique<SkCanvas>(bitmap, *props) :
2843 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002844}
reedd5fa1a42014-08-09 11:08:05 -07002845
2846///////////////////////////////////////////////////////////////////////////////
2847
Florin Malitaee424ac2016-12-01 12:47:59 -05002848SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
Hal Canary363a3f82018-10-04 11:04:48 -04002849 : INHERITED(SkIRect::MakeWH(width, height)) {}
Florin Malitaee424ac2016-12-01 12:47:59 -05002850
Florin Malita439ace92016-12-02 12:05:41 -05002851SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
Hal Canary363a3f82018-10-04 11:04:48 -04002852 : INHERITED(bounds) {}
Florin Malita439ace92016-12-02 12:05:41 -05002853
Herb Derbyefe39bc2018-05-01 17:06:20 -04002854SkNoDrawCanvas::SkNoDrawCanvas(sk_sp<SkBaseDevice> device)
Herb Derby76d69b42018-03-15 17:34:40 -04002855 : INHERITED(device) {}
2856
Florin Malitaee424ac2016-12-01 12:47:59 -05002857SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2858 (void)this->INHERITED::getSaveLayerStrategy(rec);
2859 return kNoLayer_SaveLayerStrategy;
2860}
2861
2862///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002863
reed73603f32016-09-20 08:42:38 -07002864static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2865static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2866static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2867static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2868static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2869static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002870
2871///////////////////////////////////////////////////////////////////////////////////////////////////
2872
2873SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2874 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002875 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002876 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2877 SkIPoint origin = dev->getOrigin();
2878 SkMatrix ctm = this->getTotalMatrix();
2879 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2880
2881 SkIRect clip = fMCRec->fRasterClip.getBounds();
2882 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002883 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002884 clip.setEmpty();
2885 }
2886
2887 fAllocator->updateHandle(handle, ctm, clip);
2888 return handle;
2889 }
2890 return nullptr;
2891}
2892
2893static bool install(SkBitmap* bm, const SkImageInfo& info,
2894 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002895 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002896}
2897
2898SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2899 SkBitmap* bm) {
2900 SkRasterHandleAllocator::Rec rec;
2901 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2902 return nullptr;
2903 }
2904 return rec.fHandle;
2905}
2906
2907std::unique_ptr<SkCanvas>
2908SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2909 const SkImageInfo& info, const Rec* rec) {
2910 if (!alloc || !supported_for_raster_canvas(info)) {
2911 return nullptr;
2912 }
2913
2914 SkBitmap bm;
2915 Handle hndl;
2916
2917 if (rec) {
2918 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2919 } else {
2920 hndl = alloc->allocBitmap(info, &bm);
2921 }
2922 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2923}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002924
2925///////////////////////////////////////////////////////////////////////////////////////////////////
2926
2927