blob: 24a6d4ab26ad837821bdd2f15a006567dbc6f138 [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
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060023#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080024#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000025#include "SkMetaData.h"
Ben Wagner4bd3b092017-08-01 13:22:23 -040026#include "SkMSAN.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050027#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070028#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070029#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070030#include "SkPatchUtils.h"
Mike Klein88d90712018-01-27 17:30:04 +000031#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000032#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050033#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
Cary Clark2a475ea2017-04-28 15:35:12 -040036#include "SkString.h"
reed@google.com97af1a62012-08-28 12:19:02 +000037#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070038#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000039#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000040#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080041#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070042#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000044#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080045#include "GrContext.h"
Brian Osman3b655982017-03-07 16:58:08 -050046#include "SkGr.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070047
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050049#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050050#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051
reede3b38ce2016-01-08 09:18:44 -080052#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
Mike Reed74d6e112018-01-23 13:06:12 -050053#define RETURN_ON_FALSE(pred) do { if (!(pred)) return; } while (0)
reede3b38ce2016-01-08 09:18:44 -080054
Mike Reed139e5e02017-03-08 11:29:33 -050055///////////////////////////////////////////////////////////////////////////////////////////////////
56
reedc83a2972015-07-16 07:40:45 -070057/*
58 * Return true if the drawing this rect would hit every pixels in the canvas.
59 *
60 * Returns false if
61 * - rect does not contain the canvas' bounds
62 * - paint is not fill
63 * - paint would blur or otherwise change the coverage of the rect
64 */
65bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
66 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070067 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
68 (int)kNone_ShaderOverrideOpacity,
69 "need_matching_enums0");
70 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
71 (int)kOpaque_ShaderOverrideOpacity,
72 "need_matching_enums1");
73 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
74 (int)kNotOpaque_ShaderOverrideOpacity,
75 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070076
77 const SkISize size = this->getBaseLayerSize();
78 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050079
80 // if we're clipped at all, we can't overwrite the entire surface
81 {
82 SkBaseDevice* base = this->getDevice();
83 SkBaseDevice* top = this->getTopDevice();
84 if (base != top) {
85 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
86 }
87 if (!base->clipIsWideOpen()) {
88 return false;
89 }
reedc83a2972015-07-16 07:40:45 -070090 }
91
92 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070093 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070094 return false; // conservative
95 }
halcanaryc5769b22016-08-10 07:13:21 -070096
97 SkRect devRect;
98 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
99 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -0700100 return false;
101 }
102 }
103
104 if (paint) {
105 SkPaint::Style paintStyle = paint->getStyle();
106 if (!(paintStyle == SkPaint::kFill_Style ||
107 paintStyle == SkPaint::kStrokeAndFill_Style)) {
108 return false;
109 }
110 if (paint->getMaskFilter() || paint->getLooper()
111 || paint->getPathEffect() || paint->getImageFilter()) {
112 return false; // conservative
113 }
114 }
115 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
116}
117
118///////////////////////////////////////////////////////////////////////////////////////////////////
119
reed@google.comda17f752012-08-16 18:27:05 +0000120// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121//#define SK_TRACE_SAVERESTORE
122
123#ifdef SK_TRACE_SAVERESTORE
124 static int gLayerCounter;
125 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
126 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
127
128 static int gRecCounter;
129 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
130 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
131
132 static int gCanvasCounter;
133 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
134 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
135#else
136 #define inc_layer()
137 #define dec_layer()
138 #define inc_rec()
139 #define dec_rec()
140 #define inc_canvas()
141 #define dec_canvas()
142#endif
143
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000144typedef SkTLazy<SkPaint> SkLazyPaint;
145
reedc83a2972015-07-16 07:40:45 -0700146void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000147 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700148 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
149 ? SkSurface::kDiscard_ContentChangeMode
150 : SkSurface::kRetain_ContentChangeMode);
151 }
152}
153
154void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
155 ShaderOverrideOpacity overrideOpacity) {
156 if (fSurfaceBase) {
157 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
158 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
159 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
160 // and therefore we don't care which mode we're in.
161 //
162 if (fSurfaceBase->outstandingImageSnapshot()) {
163 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
164 mode = SkSurface::kDiscard_ContentChangeMode;
165 }
166 }
167 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000168 }
169}
170
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000173/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174 The clip/matrix/proc are fields that reflect the top of the save/restore
175 stack. Whenever the canvas changes, it marks a dirty flag, and then before
176 these are used (assuming we're not on a layer) we rebuild these cache
177 values: they reflect the top of the save stack, but translated and clipped
178 by the device's XY offset and bitmap-bounds.
179*/
180struct DeviceCM {
Florin Malita713b8ef2017-04-28 10:57:24 -0400181 DeviceCM* fNext;
182 sk_sp<SkBaseDevice> fDevice;
183 SkRasterClip fClip;
184 std::unique_ptr<const SkPaint> fPaint; // may be null (in the future)
185 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
Florin Malita53f77bd2017-04-28 13:48:37 -0400186 sk_sp<SkImage> fClipImage;
187 SkMatrix fClipMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188
Florin Malita53f77bd2017-04-28 13:48:37 -0400189 DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed,
Mike Kleinb34ab042017-05-01 21:34:14 +0000190 const SkImage* clipImage, const SkMatrix* clipMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -0700191 : fNext(nullptr)
Florin Malita713b8ef2017-04-28 10:57:24 -0400192 , fDevice(std::move(device))
193 , fPaint(paint ? skstd::make_unique<SkPaint>(*paint) : nullptr)
reed8c30a812016-04-20 16:36:51 -0700194 , fStashedMatrix(stashed)
Mike Kleinb34ab042017-05-01 21:34:14 +0000195 , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage)))
Florin Malita53f77bd2017-04-28 13:48:37 -0400196 , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I())
Florin Malita713b8ef2017-04-28 10:57:24 -0400197 {}
reed@google.com4b226022011-01-11 18:32:13 +0000198
mtkleinfeaadee2015-04-08 11:25:48 -0700199 void reset(const SkIRect& bounds) {
200 SkASSERT(!fPaint);
201 SkASSERT(!fNext);
202 SkASSERT(fDevice);
203 fClip.setRect(bounds);
204 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205};
206
207/* This is the record we keep for each save/restore level in the stack.
208 Since a level optionally copies the matrix and/or stack, we have pointers
209 for these fields. If the value is copied for this level, the copy is
210 stored in the ...Storage field, and the pointer points to that. If the
211 value is not copied for this level, we ignore ...Storage, and just point
212 at the corresponding value in the previous level in the stack.
213*/
214class SkCanvas::MCRec {
215public:
reed1f836ee2014-07-07 07:49:34 -0700216 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700217 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 /* If there are any layers in the stack, this points to the top-most
219 one that is at or below this level in the stack (so we know what
220 bitmap/device to draw into from this level. This value is NOT
221 reference counted, since the real owner is either our fLayer field,
222 or a previous one in a lower level.)
223 */
Mike Reeda1361362017-03-07 09:37:29 -0500224 DeviceCM* fTopLayer;
225 SkConservativeClip fRasterClip;
226 SkMatrix fMatrix;
227 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228
Mike Reeda1361362017-03-07 09:37:29 -0500229 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700230 fFilter = nullptr;
231 fLayer = nullptr;
232 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800233 fMatrix.reset();
234 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700235
reedd9544982014-09-09 18:46:22 -0700236 // don't bother initializing fNext
237 inc_rec();
238 }
Jim Van Verth343fe492017-05-02 16:49:24 -0400239 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700240 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700241 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700242 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800243 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700244
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 // don't bother initializing fNext
246 inc_rec();
247 }
248 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000249 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700250 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 dec_rec();
252 }
mtkleinfeaadee2015-04-08 11:25:48 -0700253
254 void reset(const SkIRect& bounds) {
255 SkASSERT(fLayer);
256 SkASSERT(fDeferredSaveCount == 0);
257
258 fMatrix.reset();
259 fRasterClip.setRect(bounds);
260 fLayer->reset(bounds);
261 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262};
263
Mike Reeda1361362017-03-07 09:37:29 -0500264class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265public:
Mike Reeda1361362017-03-07 09:37:29 -0500266 SkDrawIter(SkCanvas* canvas)
267 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
268 {}
reed@google.com4b226022011-01-11 18:32:13 +0000269
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000271 const DeviceCM* rec = fCurrLayer;
272 if (rec && rec->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -0400273 fDevice = rec->fDevice.get();
274 fPaint = rec->fPaint.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700276 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 return true;
278 }
279 return false;
280 }
reed@google.com4b226022011-01-11 18:32:13 +0000281
reed@google.com6f8f2922011-03-04 22:27:10 +0000282 int getX() const { return fDevice->getOrigin().x(); }
283 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000285
Mike Reed99330ba2017-02-22 11:01:08 -0500286 SkBaseDevice* fDevice;
287
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289 const DeviceCM* fCurrLayer;
290 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291};
292
Florin Malita713b8ef2017-04-28 10:57:24 -0400293#define FOR_EACH_TOP_DEVICE( code ) \
294 do { \
295 DeviceCM* layer = fMCRec->fTopLayer; \
296 while (layer) { \
297 SkBaseDevice* device = layer->fDevice.get(); \
298 if (device) { \
299 code; \
300 } \
301 layer = layer->fNext; \
302 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500303 } while (0)
304
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305/////////////////////////////////////////////////////////////////////////////
306
reeddbc3cef2015-04-29 12:18:57 -0700307static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
308 return lazy->isValid() ? lazy->get() : lazy->set(orig);
309}
310
311/**
312 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700313 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700314 */
reedd053ce92016-03-22 10:17:23 -0700315static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700316 SkImageFilter* imgf = paint.getImageFilter();
317 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700318 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700319 }
320
reedd053ce92016-03-22 10:17:23 -0700321 SkColorFilter* imgCFPtr;
322 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700323 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700324 }
reedd053ce92016-03-22 10:17:23 -0700325 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700326
327 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700328 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700329 // there is no existing paint colorfilter, so we can just return the imagefilter's
330 return imgCF;
331 }
332
333 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
334 // and we need to combine them into a single colorfilter.
Mike Reed19d7bd62018-02-19 14:10:57 -0500335 return imgCF->makeComposed(sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700336}
337
senorblanco87e066e2015-10-28 11:23:36 -0700338/**
339 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
340 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
341 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
342 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
343 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
344 * conservative "effective" bounds based on the settings in the paint... with one exception. This
345 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
346 * deliberately ignored.
347 */
348static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
349 const SkRect& rawBounds,
350 SkRect* storage) {
351 SkPaint tmpUnfiltered(paint);
352 tmpUnfiltered.setImageFilter(nullptr);
353 if (tmpUnfiltered.canComputeFastBounds()) {
354 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
355 } else {
356 return rawBounds;
357 }
358}
359
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360class AutoDrawLooper {
361public:
senorblanco87e066e2015-10-28 11:23:36 -0700362 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
363 // paint. It's used to determine the size of the offscreen layer for filters.
364 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700365 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700366 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000367 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800368#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800370#else
371 fFilter = nullptr;
372#endif
reed4a8126e2014-09-22 07:29:03 -0700373 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000374 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700375 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000376 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377
reedd053ce92016-03-22 10:17:23 -0700378 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700379 if (simplifiedCF) {
380 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700381 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700382 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700383 fPaint = paint;
384 }
385
386 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700387 /**
388 * We implement ImageFilters for a given draw by creating a layer, then applying the
389 * imagefilter to the pixels of that layer (its backing surface/image), and then
390 * we call restore() to xfer that layer to the main canvas.
391 *
392 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
393 * 2. Generate the src pixels:
394 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
395 * return (fPaint). We then draw the primitive (using srcover) into a cleared
396 * buffer/surface.
397 * 3. Restore the layer created in #1
398 * The imagefilter is passed the buffer/surface from the layer (now filled with the
399 * src pixels of the primitive). It returns a new "filtered" buffer, which we
400 * draw onto the previous layer using the xfermode from the original paint.
401 */
reed@google.com8926b162012-03-23 15:36:36 +0000402 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500403 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700404 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700405 SkRect storage;
406 if (rawBounds) {
407 // Make rawBounds include all paint outsets except for those due to image filters.
408 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
409 }
reedbfd5f172016-01-07 11:28:08 -0800410 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700411 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700412 fTempLayerForImageFilter = true;
413 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000414 }
415
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000416 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500417 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000418 fIsSimple = false;
419 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700420 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000421 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700422 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000423 }
424 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000425
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700427 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000428 fCanvas->internalRestore();
429 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000430 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000431 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000432
reed@google.com4e2b3d32011-04-07 14:18:59 +0000433 const SkPaint& paint() const {
434 SkASSERT(fPaint);
435 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000436 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000437
reed@google.com129ec222012-05-15 13:24:09 +0000438 bool next(SkDrawFilter::Type drawType) {
439 if (fDone) {
440 return false;
441 } else if (fIsSimple) {
442 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000443 return !fPaint->nothingToDraw();
444 } else {
445 return this->doNext(drawType);
446 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000447 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000448
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500450 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700451 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000452 SkCanvas* fCanvas;
453 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000454 SkDrawFilter* fFilter;
455 const SkPaint* fPaint;
456 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700457 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000458 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000459 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000460 SkDrawLooper::Context* fLooperContext;
Florin Malita14a64302017-05-24 14:53:44 -0400461 SkSTArenaAlloc<48> fAlloc;
reed@google.com129ec222012-05-15 13:24:09 +0000462
463 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000464};
465
reed@google.com129ec222012-05-15 13:24:09 +0000466bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700467 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000468 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700469 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000470
reeddbc3cef2015-04-29 12:18:57 -0700471 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
472 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000473
reed5c476fb2015-04-20 08:04:21 -0700474 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700475 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700476 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000477 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000478
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000479 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000480 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000481 return false;
482 }
483 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000484 if (!fFilter->filter(paint, drawType)) {
485 fDone = true;
486 return false;
487 }
halcanary96fcdcc2015-08-27 07:41:13 -0700488 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000489 // no looper means we only draw once
490 fDone = true;
491 }
492 }
493 fPaint = paint;
494
495 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000496 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000497 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000498 }
499
500 // call this after any possible paint modifiers
501 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700502 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000503 return false;
504 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000505 return true;
506}
507
reed@android.com8a1c16f2008-12-17 15:59:43 +0000508////////// macros to place around the internal draw calls //////////////////
509
reed3aafe112016-08-18 12:45:34 -0700510#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
511 this->predrawNotify(); \
512 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
513 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800514 SkDrawIter iter(this);
515
516
reed@google.com8926b162012-03-23 15:36:36 +0000517#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000518 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700519 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000520 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000521 SkDrawIter iter(this);
522
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000523#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000524 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700525 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000526 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000527 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000528
reedc83a2972015-07-16 07:40:45 -0700529#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
530 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700531 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700532 while (looper.next(type)) { \
533 SkDrawIter iter(this);
534
reed@google.com4e2b3d32011-04-07 14:18:59 +0000535#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000536
537////////////////////////////////////////////////////////////////////////////
538
msarettfbfa2582016-08-12 08:29:08 -0700539static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
540 if (bounds.isEmpty()) {
541 return SkRect::MakeEmpty();
542 }
543
544 // Expand bounds out by 1 in case we are anti-aliasing. We store the
545 // bounds as floats to enable a faster quick reject implementation.
546 SkRect dst;
547 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
548 return dst;
549}
550
mtkleinfeaadee2015-04-08 11:25:48 -0700551void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
552 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700553 fMCRec->reset(bounds);
554
555 // We're peering through a lot of structs here. Only at this scope do we
Mike Reed139e5e02017-03-08 11:29:33 -0500556 // know that the device is a SkNoPixelsDevice.
Florin Malita713b8ef2017-04-28 10:57:24 -0400557 static_cast<SkNoPixelsDevice*>(fMCRec->fLayer->fDevice.get())->resetForNextPicture(bounds);
msarettfbfa2582016-08-12 08:29:08 -0700558 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700559 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700560}
561
reedd9544982014-09-09 18:46:22 -0700562SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800563 if (device && device->forceConservativeRasterClip()) {
564 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
565 }
reed42b73eb2015-11-20 13:42:42 -0800566
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000567 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800568 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700569 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000570
571 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500572 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500573 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700574 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575
reeda499f902015-05-01 09:34:31 -0700576 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
577 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Florin Malita53f77bd2017-04-28 13:48:37 -0400578 new (fDeviceCMStorage) DeviceCM(sk_ref_sp(device), nullptr, fMCRec->fMatrix, nullptr, nullptr);
reedb679ca82015-04-07 04:40:48 -0700579
reed@android.com8a1c16f2008-12-17 15:59:43 +0000580 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000581
halcanary96fcdcc2015-08-27 07:41:13 -0700582 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000583
reedf92c8662014-08-18 08:02:43 -0700584 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700585 // The root device and the canvas should always have the same pixel geometry
586 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed78e27682014-11-19 08:04:34 -0800587 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700588 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500589
Mike Reedc42a1cd2017-02-14 14:25:14 -0500590 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700591 }
msarettfbfa2582016-08-12 08:29:08 -0700592
reedf92c8662014-08-18 08:02:43 -0700593 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000594}
595
reed@google.comcde92112011-07-06 20:00:52 +0000596SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000597 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700598 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000599{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000600 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000601
halcanary96fcdcc2015-08-27 07:41:13 -0700602 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000603}
604
reed96a857e2015-01-25 10:33:58 -0800605SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000606 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800607 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000608{
609 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700610
Mike Reed566e53c2017-03-10 10:49:45 -0500611 this->init(new SkNoPixelsDevice(SkIRect::MakeWH(SkTMax(width, 0), SkTMax(height, 0)), fProps),
halcanary385fe4d2015-08-26 13:07:48 -0700612 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700613}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000614
reed78e27682014-11-19 08:04:34 -0800615SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700616 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700617 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700618{
619 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700620
Mike Reed566e53c2017-03-10 10:49:45 -0500621 SkIRect r = bounds.isEmpty() ? SkIRect::MakeEmpty() : bounds;
622 this->init(new SkNoPixelsDevice(r, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700623}
624
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000625SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000626 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700627 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000628{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000629 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700630
reedd9544982014-09-09 18:46:22 -0700631 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000632}
633
robertphillipsfcf78292015-06-19 11:49:52 -0700634SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
635 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700636 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700637{
638 inc_canvas();
639
640 this->init(device, flags);
641}
642
reed4a8126e2014-09-22 07:29:03 -0700643SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700644 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700645 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700646{
647 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700648
Hal Canary704cd322016-11-07 14:13:52 -0500649 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
650 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700651}
reed29c857d2014-09-21 10:25:07 -0700652
Mike Reed356f7c22017-01-10 11:58:39 -0500653SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
654 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700655 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
656 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500657 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700658{
659 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700660
Mike Reed356f7c22017-01-10 11:58:39 -0500661 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500662 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663}
664
Mike Reed356f7c22017-01-10 11:58:39 -0500665SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
666
Matt Sarett31f99ce2017-04-11 08:46:01 -0400667#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
668SkCanvas::SkCanvas(const SkBitmap& bitmap, ColorBehavior)
669 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
670 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
671 , fAllocator(nullptr)
672{
673 inc_canvas();
674
675 SkBitmap tmp(bitmap);
676 *const_cast<SkImageInfo*>(&tmp.info()) = tmp.info().makeColorSpace(nullptr);
677 sk_sp<SkBaseDevice> device(new SkBitmapDevice(tmp, fProps, nullptr));
678 this->init(device.get(), kDefault_InitFlags);
679}
680#endif
681
reed@android.com8a1c16f2008-12-17 15:59:43 +0000682SkCanvas::~SkCanvas() {
683 // free up the contents of our deque
684 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000685
reed@android.com8a1c16f2008-12-17 15:59:43 +0000686 this->internalRestore(); // restore the last, since we're going away
687
halcanary385fe4d2015-08-26 13:07:48 -0700688 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000689
reed@android.com8a1c16f2008-12-17 15:59:43 +0000690 dec_canvas();
691}
692
fmalita53d9f1c2016-01-25 06:23:54 -0800693#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000694SkDrawFilter* SkCanvas::getDrawFilter() const {
695 return fMCRec->fFilter;
696}
697
698SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700699 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000700 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
701 return filter;
702}
fmalita77650002016-01-21 18:47:11 -0800703#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000704
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000705SkMetaData& SkCanvas::getMetaData() {
706 // metadata users are rare, so we lazily allocate it. If that changes we
707 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700708 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000709 fMetaData = new SkMetaData;
710 }
711 return *fMetaData;
712}
713
reed@android.com8a1c16f2008-12-17 15:59:43 +0000714///////////////////////////////////////////////////////////////////////////////
715
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000716void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700717 this->onFlush();
718}
719
720void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000721 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000722 if (device) {
723 device->flush();
724 }
725}
726
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000727SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000728 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000729 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
730}
731
senorblancoafc7cce2016-02-02 18:44:15 -0800732SkIRect SkCanvas::getTopLayerBounds() const {
733 SkBaseDevice* d = this->getTopDevice();
734 if (!d) {
735 return SkIRect::MakeEmpty();
736 }
737 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
738}
739
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000740SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000741 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000742 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000743 SkASSERT(rec && rec->fLayer);
Florin Malita713b8ef2017-04-28 10:57:24 -0400744 return rec->fLayer->fDevice.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000745}
746
Florin Malita0ed3b642017-01-13 16:56:38 +0000747SkBaseDevice* SkCanvas::getTopDevice() const {
Florin Malita713b8ef2017-04-28 10:57:24 -0400748 return fMCRec->fTopLayer->fDevice.get();
reed@google.com9266fed2011-03-30 00:18:03 +0000749}
750
Mike Reed353196f2017-07-21 11:01:18 -0400751bool SkCanvas::readPixels(const SkPixmap& pm, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000752 SkBaseDevice* device = this->getDevice();
Mike Reed353196f2017-07-21 11:01:18 -0400753 return device && pm.addr() && device->readPixels(pm, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000754}
755
Mike Reed353196f2017-07-21 11:01:18 -0400756bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
757 return this->readPixels({ dstInfo, dstP, rowBytes}, x, y);
Mike Reed12e946b2017-04-17 10:53:29 -0400758}
759
760bool SkCanvas::readPixels(const SkBitmap& bm, int x, int y) {
761 SkPixmap pm;
762 return bm.peekPixels(&pm) && this->readPixels(pm, x, y);
763}
764
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000765bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
Mike Reed4edb5d22017-04-17 11:02:51 -0400766 SkPixmap pm;
767 if (bitmap.peekPixels(&pm)) {
reedcf01e312015-05-23 19:14:51 -0700768 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000769 }
770 return false;
771}
772
Matt Sarett03dd6d52017-01-23 12:15:09 -0500773bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000774 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000775 SkBaseDevice* device = this->getDevice();
776 if (!device) {
777 return false;
778 }
779
Matt Sarett03dd6d52017-01-23 12:15:09 -0500780 // This check gives us an early out and prevents generation ID churn on the surface.
781 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
782 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
783 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
784 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000785 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000786
Matt Sarett03dd6d52017-01-23 12:15:09 -0500787 // Tell our owning surface to bump its generation ID.
788 const bool completeOverwrite =
789 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700790 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700791
Matt Sarett03dd6d52017-01-23 12:15:09 -0500792 // This can still fail, most notably in the case of a invalid color type or alpha type
793 // conversion. We could pull those checks into this function and avoid the unnecessary
794 // generation ID bump. But then we would be performing those checks twice, since they
795 // are also necessary at the bitmap/pixmap entry points.
Mike Reed353196f2017-07-21 11:01:18 -0400796 return device->writePixels({srcInfo, pixels, rowBytes}, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000797}
reed@google.com51df9e32010-12-23 19:29:18 +0000798
reed@android.com8a1c16f2008-12-17 15:59:43 +0000799//////////////////////////////////////////////////////////////////////////////
800
reed2ff1fce2014-12-11 07:07:37 -0800801void SkCanvas::checkForDeferredSave() {
802 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800803 this->doSave();
804 }
805}
806
reedf0090cb2014-11-26 08:55:51 -0800807int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800808#ifdef SK_DEBUG
809 int count = 0;
810 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
811 for (;;) {
812 const MCRec* rec = (const MCRec*)iter.next();
813 if (!rec) {
814 break;
815 }
816 count += 1 + rec->fDeferredSaveCount;
817 }
818 SkASSERT(count == fSaveCount);
819#endif
820 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800821}
822
823int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800824 fSaveCount += 1;
825 fMCRec->fDeferredSaveCount += 1;
826 return this->getSaveCount() - 1; // return our prev value
827}
828
829void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800830 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700831
832 SkASSERT(fMCRec->fDeferredSaveCount > 0);
833 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800834 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800835}
836
837void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800838 if (fMCRec->fDeferredSaveCount > 0) {
839 SkASSERT(fSaveCount > 1);
840 fSaveCount -= 1;
841 fMCRec->fDeferredSaveCount -= 1;
842 } else {
843 // check for underflow
844 if (fMCStack.count() > 1) {
845 this->willRestore();
846 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700847 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800848 this->internalRestore();
849 this->didRestore();
850 }
reedf0090cb2014-11-26 08:55:51 -0800851 }
852}
853
854void SkCanvas::restoreToCount(int count) {
855 // sanity check
856 if (count < 1) {
857 count = 1;
858 }
mtkleinf0f14112014-12-12 08:46:25 -0800859
reedf0090cb2014-11-26 08:55:51 -0800860 int n = this->getSaveCount() - count;
861 for (int i = 0; i < n; ++i) {
862 this->restore();
863 }
864}
865
reed2ff1fce2014-12-11 07:07:37 -0800866void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700868 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000869 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000870
Mike Reedc42a1cd2017-02-14 14:25:14 -0500871 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000872}
873
reed4960eee2015-12-18 07:09:18 -0800874bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
Cary Clark7eddfb82018-03-13 14:41:10 -0400875 return !(saveLayerFlags & SkCanvasPriv::kDontClipToLayer_SaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000876}
877
reed4960eee2015-12-18 07:09:18 -0800878bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700879 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500880 SkIRect clipBounds = this->getDeviceClipBounds();
881 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000882 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000883 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000884
reed96e657d2015-03-10 17:30:07 -0700885 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
886
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000887 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700888 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800889 if (bounds && !imageFilter->canComputeFastBounds()) {
890 bounds = nullptr;
891 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000892 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000893 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700894 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000895 SkRect r;
reed96e657d2015-03-10 17:30:07 -0700896 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000897 r.roundOut(&ir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000898 } else { // no user bounds, so just use the clip
899 ir = clipBounds;
900 }
Xianzhu Wang3b428cb2018-01-22 09:51:13 -0800901
902 // early exit if the layer's bounds are clipped out
903 if (!ir.intersect(clipBounds)) {
904 if (BoundsAffectsClip(saveLayerFlags)) {
905 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
906 fMCRec->fRasterClip.setEmpty();
907 fDeviceClipBounds.setEmpty();
908 }
909 return false;
910 }
reed180aec42015-03-11 10:39:04 -0700911 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000912
reed4960eee2015-12-18 07:09:18 -0800913 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700914 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700915 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700916 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000917 }
918
919 if (intersection) {
920 *intersection = ir;
921 }
922 return true;
923}
924
reed4960eee2015-12-18 07:09:18 -0800925int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
926 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000927}
928
reed70ee31b2015-12-10 13:44:45 -0800929int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -0800930 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
931}
932
Cary Clarke041e312018-03-06 13:00:52 -0500933int SkCanvas::saveLayer(const SaveLayerRec& rec) {
934 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
reed4960eee2015-12-18 07:09:18 -0800935 fSaveCount += 1;
Cary Clarke041e312018-03-06 13:00:52 -0500936 this->internalSaveLayer(rec, strategy);
reed4960eee2015-12-18 07:09:18 -0800937 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -0800938}
939
reeda2217ef2016-07-20 06:04:34 -0700940void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -0500941 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -0500942 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -0700943 SkDraw draw;
944 SkRasterClip rc;
945 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
946 if (!dst->accessPixels(&draw.fDst)) {
947 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -0800948 }
reeda2217ef2016-07-20 06:04:34 -0700949 draw.fMatrix = &SkMatrix::I();
950 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -0800951
952 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -0500953 if (filter) {
954 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
955 }
reeda2217ef2016-07-20 06:04:34 -0700956
Mike Reedc42a1cd2017-02-14 14:25:14 -0500957 int x = src->getOrigin().x() - dstOrigin.x();
958 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -0700959 auto special = src->snapSpecial();
960 if (special) {
Florin Malita53f77bd2017-04-28 13:48:37 -0400961 dst->drawSpecial(special.get(), x, y, p, nullptr, SkMatrix::I());
reeda2217ef2016-07-20 06:04:34 -0700962 }
robertphillips7354a4b2015-12-16 05:08:27 -0800963}
reed70ee31b2015-12-10 13:44:45 -0800964
Mike Kleine083f7c2018-02-07 12:54:27 -0500965static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, const SkPaint* paint) {
Mike Klein649fb732018-02-26 15:09:16 -0500966 // Need to force L32 for now if we have an image filter.
967 // If filters ever support other colortypes, e.g. sRGB or F16, we can remove this check.
968 if (paint && paint->getImageFilter()) {
Mike Kleine083f7c2018-02-07 12:54:27 -0500969 return SkImageInfo::MakeN32Premul(w, h);
reed129ed1c2016-02-22 06:42:31 -0800970 }
Mike Klein649fb732018-02-26 15:09:16 -0500971
972 SkColorType ct = prev.colorType();
973 if (prev.bytesPerPixel() <= 4) {
974 // "Upgrade" A8, G8, 565, 4444, 1010102, 101010x, and 888x to 8888,
975 // ensuring plenty of alpha bits for the layer, perhaps losing some color bits in return.
976 ct = kN32_SkColorType;
977 }
978 return SkImageInfo::Make(w, h, ct, kPremul_SkAlphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -0800979}
980
reed4960eee2015-12-18 07:09:18 -0800981void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
982 const SkRect* bounds = rec.fBounds;
983 const SkPaint* paint = rec.fPaint;
984 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
985
reed8c30a812016-04-20 16:36:51 -0700986 SkLazyPaint lazyP;
Ben Wagnera93a14a2017-08-28 10:34:05 -0400987 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : nullptr;
reed8c30a812016-04-20 16:36:51 -0700988 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -0700989 SkMatrix remainder;
990 SkSize scale;
991 /*
992 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
993 * but they do handle scaling. To accommodate this, we do the following:
994 *
995 * 1. Stash off the current CTM
996 * 2. Decompose the CTM into SCALE and REMAINDER
997 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
998 * contains the REMAINDER
999 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1000 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1001 * of the original imagefilter, and draw that (via drawSprite)
1002 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1003 *
1004 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1005 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1006 */
reed96a04f32016-04-25 09:25:15 -07001007 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001008 stashedMatrix.decomposeScale(&scale, &remainder))
1009 {
1010 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1011 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1012 SkPaint* p = lazyP.set(*paint);
1013 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1014 SkFilterQuality::kLow_SkFilterQuality,
1015 sk_ref_sp(imageFilter)));
1016 imageFilter = p->getImageFilter();
1017 paint = p;
1018 }
reed8c30a812016-04-20 16:36:51 -07001019
junov@chromium.orga907ac32012-02-24 21:54:07 +00001020 // do this before we create the layer. We don't call the public save() since
1021 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001022 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001023
junov@chromium.orga907ac32012-02-24 21:54:07 +00001024 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001025 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001026 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001027 }
1028
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001029 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1030 // the clipRectBounds() call above?
1031 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001032 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001033 }
1034
reed8dc0ccb2015-03-20 06:32:52 -07001035 SkPixelGeometry geo = fProps.pixelGeometry();
1036 if (paint) {
reed76033be2015-03-14 10:54:31 -07001037 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001038 if (paint->getImageFilter() || paint->getColorFilter()) {
reed8dc0ccb2015-03-20 06:32:52 -07001039 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001040 }
1041 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001042
robertphillips5139e502016-07-19 05:10:40 -07001043 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001044 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001045 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001046 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001047 }
reedb2db8982014-11-13 12:41:02 -08001048
Mike Kleine083f7c2018-02-07 12:54:27 -05001049 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), paint);
reed129ed1c2016-02-22 06:42:31 -08001050
Hal Canary704cd322016-11-07 14:13:52 -05001051 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001052 {
reed70ee31b2015-12-10 13:44:45 -08001053 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001054 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001055 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001056 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001057 preserveLCDText,
1058 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001059 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1060 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001061 return;
reed61f501f2015-04-29 08:34:00 -07001062 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001063 }
Florin Malita53f77bd2017-04-28 13:48:37 -04001064 DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001065
Mike Reedb43a3e02017-02-11 10:18:58 -05001066 // only have a "next" if this new layer doesn't affect the clip (rare)
1067 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001068 fMCRec->fLayer = layer;
1069 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001070
Mike Reedc61abee2017-02-28 17:45:27 -05001071 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001072 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001073 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001074 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001075
Mike Reedc42a1cd2017-02-14 14:25:14 -05001076 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1077
1078 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1079 if (layer->fNext) {
1080 // need to punch a hole in the previous device, so we don't draw there, given that
1081 // the new top-layer will allow drawing to happen "below" it.
1082 SkRegion hole(ir);
1083 do {
1084 layer = layer->fNext;
1085 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1086 } while (layer->fNext);
1087 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088}
1089
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001090int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001091 if (0xFF == alpha) {
1092 return this->saveLayer(bounds, nullptr);
1093 } else {
1094 SkPaint tmpPaint;
1095 tmpPaint.setAlpha(alpha);
1096 return this->saveLayer(bounds, &tmpPaint);
1097 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001098}
1099
reed@android.com8a1c16f2008-12-17 15:59:43 +00001100void SkCanvas::internalRestore() {
1101 SkASSERT(fMCStack.count() != 0);
1102
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001103 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001104 DeviceCM* layer = fMCRec->fLayer; // may be null
1105 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001106 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001107
1108 // now do the normal restore()
1109 fMCRec->~MCRec(); // balanced in save()
1110 fMCStack.pop_back();
1111 fMCRec = (MCRec*)fMCStack.back();
1112
Mike Reedc42a1cd2017-02-14 14:25:14 -05001113 if (fMCRec) {
1114 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1115 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001116
reed@android.com8a1c16f2008-12-17 15:59:43 +00001117 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1118 since if we're being recorded, we don't want to record this (the
1119 recorder will have already recorded the restore).
1120 */
bsalomon49f085d2014-09-05 13:34:00 -07001121 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001122 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001123 const SkIPoint& origin = layer->fDevice->getOrigin();
Florin Malita713b8ef2017-04-28 10:57:24 -04001124 this->internalDrawDevice(layer->fDevice.get(), origin.x(), origin.y(),
Florin Malita53f77bd2017-04-28 13:48:37 -04001125 layer->fPaint.get(),
1126 layer->fClipImage.get(), layer->fClipMatrix);
reed8c30a812016-04-20 16:36:51 -07001127 // restore what we smashed in internalSaveLayer
1128 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001129 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001130 delete layer;
reedb679ca82015-04-07 04:40:48 -07001131 } else {
1132 // we're at the root
reeda499f902015-05-01 09:34:31 -07001133 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001134 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001135 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001136 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001137 }
msarettfbfa2582016-08-12 08:29:08 -07001138
1139 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001140 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001141 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1142 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001143}
1144
reede8f30622016-03-23 18:59:25 -07001145sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001146 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001147 props = &fProps;
1148 }
1149 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001150}
1151
reede8f30622016-03-23 18:59:25 -07001152sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001153 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001154 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001155}
1156
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001157SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001158 return this->onImageInfo();
1159}
1160
1161SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001162 SkBaseDevice* dev = this->getDevice();
1163 if (dev) {
1164 return dev->imageInfo();
1165 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001166 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001167 }
1168}
1169
brianosman898235c2016-04-06 07:38:23 -07001170bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001171 return this->onGetProps(props);
1172}
1173
1174bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001175 SkBaseDevice* dev = this->getDevice();
1176 if (dev) {
1177 if (props) {
1178 *props = fProps;
1179 }
1180 return true;
1181 } else {
1182 return false;
1183 }
1184}
1185
reed6ceeebd2016-03-09 14:26:26 -08001186bool SkCanvas::peekPixels(SkPixmap* pmap) {
1187 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001188}
1189
reed884e97c2015-05-26 11:31:54 -07001190bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001191 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001192 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001193}
1194
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001195void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001196 SkPixmap pmap;
1197 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001198 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001199 }
1200 if (info) {
1201 *info = pmap.info();
1202 }
1203 if (rowBytes) {
1204 *rowBytes = pmap.rowBytes();
1205 }
1206 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001207 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001208 }
reed884e97c2015-05-26 11:31:54 -07001209 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001210}
1211
reed884e97c2015-05-26 11:31:54 -07001212bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001213 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001214 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001215}
1216
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218
Florin Malita53f77bd2017-04-28 13:48:37 -04001219void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint,
1220 SkImage* clipImage, const SkMatrix& clipMatrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001222 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223 paint = &tmp;
1224 }
reed@google.com4b226022011-01-11 18:32:13 +00001225
reed@google.com8926b162012-03-23 15:36:36 +00001226 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001227
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001229 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001230 paint = &looper.paint();
1231 SkImageFilter* filter = paint->getImageFilter();
1232 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Florin Malita53f77bd2017-04-28 13:48:37 -04001233 if (filter || clipImage) {
Robert Phillips833dcf42016-11-18 08:44:13 -05001234 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1235 if (specialImage) {
Florin Malita53f77bd2017-04-28 13:48:37 -04001236 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint,
1237 clipImage, clipMatrix);
Robert Phillips833dcf42016-11-18 08:44:13 -05001238 }
reed@google.com76dd2772012-01-05 21:15:07 +00001239 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001240 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001241 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242 }
reeda2217ef2016-07-20 06:04:34 -07001243
reed@google.com4e2b3d32011-04-07 14:18:59 +00001244 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245}
1246
reed32704672015-12-16 08:27:10 -08001247/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001248
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001249void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001250 if (dx || dy) {
1251 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001252 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001253
reedfe69b502016-09-12 06:31:48 -07001254 // Translate shouldn't affect the is-scale-translateness of the matrix.
1255 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001256
Mike Reedc42a1cd2017-02-14 14:25:14 -05001257 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001258
reedfe69b502016-09-12 06:31:48 -07001259 this->didTranslate(dx,dy);
1260 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001261}
1262
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001263void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001264 SkMatrix m;
1265 m.setScale(sx, sy);
1266 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001267}
1268
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001269void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001270 SkMatrix m;
1271 m.setRotate(degrees);
1272 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273}
1274
bungeman7438bfc2016-07-12 15:01:19 -07001275void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1276 SkMatrix m;
1277 m.setRotate(degrees, px, py);
1278 this->concat(m);
1279}
1280
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001281void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001282 SkMatrix m;
1283 m.setSkew(sx, sy);
1284 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001285}
1286
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001287void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001288 if (matrix.isIdentity()) {
1289 return;
1290 }
1291
reed2ff1fce2014-12-11 07:07:37 -08001292 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001293 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001294 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001295
Mike Reed7627fa52017-02-08 10:07:53 -05001296 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001297
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001298 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001299}
1300
reed8c30a812016-04-20 16:36:51 -07001301void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001302 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001303 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001304
Mike Reedc42a1cd2017-02-14 14:25:14 -05001305 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001306}
1307
1308void SkCanvas::setMatrix(const SkMatrix& matrix) {
1309 this->checkForDeferredSave();
1310 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001311 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001312}
1313
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001315 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001316}
1317
1318//////////////////////////////////////////////////////////////////////////////
1319
Mike Reedc1f77742016-12-09 09:00:50 -05001320void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
Mike Reed9cec1bc2018-01-19 12:57:01 -05001321 if (!rect.isFinite()) {
1322 return;
1323 }
reed2ff1fce2014-12-11 07:07:37 -08001324 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001325 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1326 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001327}
1328
Mike Reedc1f77742016-12-09 09:00:50 -05001329void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001330 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001331
Mike Reed7627fa52017-02-08 10:07:53 -05001332 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001333
reedc64eff52015-11-21 12:39:45 -08001334 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001335 fMCRec->fRasterClip.opRect(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1336 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001337 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338}
1339
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001340void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1341 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001342 if (fClipRestrictionRect.isEmpty()) {
1343 // we notify the device, but we *dont* resolve deferred saves (since we're just
1344 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001345 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001346 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001347 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001348 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001349 AutoValidateClip avc(this);
Mike Reed20800c82017-11-15 16:09:04 -05001350 fMCRec->fRasterClip.opIRect(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001351 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1352 }
1353}
1354
Mike Reedc1f77742016-12-09 09:00:50 -05001355void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001356 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001357 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001358 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001359 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1360 } else {
1361 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001362 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001363}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001364
Mike Reedc1f77742016-12-09 09:00:50 -05001365void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001366 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001367
Brian Salomona3b45d42016-10-03 11:36:16 -04001368 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001369
Mike Reed7627fa52017-02-08 10:07:53 -05001370 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001371
Mike Reed20800c82017-11-15 16:09:04 -05001372 fMCRec->fRasterClip.opRRect(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1373 isAA);
Brian Salomona3b45d42016-10-03 11:36:16 -04001374 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001375}
1376
Mike Reedc1f77742016-12-09 09:00:50 -05001377void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001378 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001379 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001380
1381 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1382 SkRect r;
1383 if (path.isRect(&r)) {
1384 this->onClipRect(r, op, edgeStyle);
1385 return;
1386 }
1387 SkRRect rrect;
1388 if (path.isOval(&r)) {
1389 rrect.setOval(r);
1390 this->onClipRRect(rrect, op, edgeStyle);
1391 return;
1392 }
1393 if (path.isRRect(&rrect)) {
1394 this->onClipRRect(rrect, op, edgeStyle);
1395 return;
1396 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001397 }
robertphillips39f05382015-11-24 09:30:12 -08001398
1399 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001400}
1401
Mike Reedc1f77742016-12-09 09:00:50 -05001402void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001403 AutoValidateClip avc(this);
1404
Brian Salomona3b45d42016-10-03 11:36:16 -04001405 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Ben Wagner63fd7602017-10-09 15:45:33 -04001406
Mike Reed7627fa52017-02-08 10:07:53 -05001407 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001408
Brian Salomona3b45d42016-10-03 11:36:16 -04001409 const SkPath* rasterClipPath = &path;
1410 const SkMatrix* matrix = &fMCRec->fMatrix;
Mike Reed20800c82017-11-15 16:09:04 -05001411 fMCRec->fRasterClip.opPath(*rasterClipPath, *matrix, this->getTopLayerBounds(),
1412 (SkRegion::Op)op, isAA);
msarettfbfa2582016-08-12 08:29:08 -07001413 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414}
1415
Mike Reedc1f77742016-12-09 09:00:50 -05001416void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001417 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001418 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001419}
1420
Mike Reedc1f77742016-12-09 09:00:50 -05001421void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001422 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001423
reed@google.com5c3d1472011-02-22 19:12:23 +00001424 AutoValidateClip avc(this);
1425
Mike Reed20800c82017-11-15 16:09:04 -05001426 fMCRec->fRasterClip.opRegion(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001427 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428}
1429
reed@google.com819c9212011-02-23 18:56:55 +00001430#ifdef SK_DEBUG
1431void SkCanvas::validateClip() const {
1432 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001433 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001434 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001435 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001436 return;
1437 }
reed@google.com819c9212011-02-23 18:56:55 +00001438}
1439#endif
1440
Mike Reeda1361362017-03-07 09:37:29 -05001441bool SkCanvas::androidFramework_isClipAA() const {
1442 bool containsAA = false;
1443
1444 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1445
1446 return containsAA;
1447}
1448
1449class RgnAccumulator {
1450 SkRegion* fRgn;
1451public:
1452 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1453 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1454 SkIPoint origin = device->getOrigin();
1455 if (origin.x() | origin.y()) {
1456 rgn->translate(origin.x(), origin.y());
1457 }
1458 fRgn->op(*rgn, SkRegion::kUnion_Op);
1459 }
1460};
1461
1462void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1463 RgnAccumulator accum(rgn);
1464 SkRegion tmp;
1465
1466 rgn->setEmpty();
1467 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001468}
1469
reed@google.com5c3d1472011-02-22 19:12:23 +00001470///////////////////////////////////////////////////////////////////////////////
1471
reed@google.com754de5f2014-02-24 19:38:20 +00001472bool SkCanvas::isClipEmpty() const {
Mike Reed02be3c12017-03-23 12:34:15 -04001473 return fMCRec->fRasterClip.isEmpty();
1474
1475 // TODO: should we only use the conservative answer in a recording canvas?
1476#if 0
Mike Reeda1361362017-03-07 09:37:29 -05001477 SkBaseDevice* dev = this->getTopDevice();
1478 // if no device we return true
1479 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
Mike Reed02be3c12017-03-23 12:34:15 -04001480#endif
reed@google.com754de5f2014-02-24 19:38:20 +00001481}
1482
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001483bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001484 SkBaseDevice* dev = this->getTopDevice();
1485 // if no device we return false
1486 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001487}
1488
msarettfbfa2582016-08-12 08:29:08 -07001489static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1490#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1491 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1492 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1493 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1494 return 0xF != _mm_movemask_ps(mask);
1495#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1496 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1497 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1498 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1499 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1500#else
1501 SkRect devRectAsRect;
1502 SkRect devClipAsRect;
1503 devRect.store(&devRectAsRect.fLeft);
1504 devClip.store(&devClipAsRect.fLeft);
1505 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1506#endif
1507}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001508
msarettfbfa2582016-08-12 08:29:08 -07001509// It's important for this function to not be inlined. Otherwise the compiler will share code
1510// between the fast path and the slow path, resulting in two slow paths.
1511static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1512 const SkMatrix& matrix) {
1513 SkRect deviceRect;
1514 matrix.mapRect(&deviceRect, src);
1515 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1516}
1517
1518bool SkCanvas::quickReject(const SkRect& src) const {
1519#ifdef SK_DEBUG
1520 // Verify that fDeviceClipBounds are set properly.
1521 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001522 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001523 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001524 } else {
msarettfbfa2582016-08-12 08:29:08 -07001525 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001526 }
msarettfbfa2582016-08-12 08:29:08 -07001527
msarett9637ea92016-08-18 14:03:30 -07001528 // Verify that fIsScaleTranslate is set properly.
1529 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001530#endif
1531
msarett9637ea92016-08-18 14:03:30 -07001532 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001533 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1534 }
1535
1536 // We inline the implementation of mapScaleTranslate() for the fast path.
1537 float sx = fMCRec->fMatrix.getScaleX();
1538 float sy = fMCRec->fMatrix.getScaleY();
1539 float tx = fMCRec->fMatrix.getTranslateX();
1540 float ty = fMCRec->fMatrix.getTranslateY();
1541 Sk4f scale(sx, sy, sx, sy);
1542 Sk4f trans(tx, ty, tx, ty);
1543
1544 // Apply matrix.
1545 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1546
1547 // Make sure left < right, top < bottom.
1548 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1549 Sk4f min = Sk4f::Min(ltrb, rblt);
1550 Sk4f max = Sk4f::Max(ltrb, rblt);
1551 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1552 // ARM this sequence generates the fastest (a single instruction).
1553 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1554
1555 // Check if the device rect is NaN or outside the clip.
1556 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001557}
1558
reed@google.com3b3e8952012-08-16 20:53:31 +00001559bool SkCanvas::quickReject(const SkPath& path) const {
1560 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001561}
1562
Mike Klein83c8dd92017-11-28 17:08:45 -05001563SkRect SkCanvas::getLocalClipBounds() const {
1564 SkIRect ibounds = this->getDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001565 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001566 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001567 }
1568
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001569 SkMatrix inverse;
1570 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001571 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001572 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001573 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001574
Mike Reed42e8c532017-01-23 14:09:13 -05001575 SkRect bounds;
1576 SkRect r;
1577 // adjust it outwards in case we are antialiasing
1578 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001579
Mike Reed42e8c532017-01-23 14:09:13 -05001580 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1581 ibounds.fRight + inset, ibounds.fBottom + inset);
1582 inverse.mapRect(&bounds, r);
1583 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001584}
1585
Mike Klein83c8dd92017-11-28 17:08:45 -05001586SkIRect SkCanvas::getDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001587 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001588}
1589
reed@android.com8a1c16f2008-12-17 15:59:43 +00001590const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001591 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001592}
1593
Brian Osman11052242016-10-27 14:47:55 -04001594GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001595 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001596 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001597}
1598
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001599GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001600 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001601 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001602}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001603
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001604void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1605 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04001606 TRACE_EVENT0("skia", TRACE_FUNC);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001607 if (outer.isEmpty()) {
1608 return;
1609 }
1610 if (inner.isEmpty()) {
1611 this->drawRRect(outer, paint);
1612 return;
1613 }
1614
1615 // We don't have this method (yet), but technically this is what we should
Cary Clarke0b72872017-04-12 12:03:15 -04001616 // be able to return ...
1617 // if (!outer.contains(inner))) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001618 //
1619 // For now at least check for containment of bounds
Cary Clarke0b72872017-04-12 12:03:15 -04001620 if (!outer.getBounds().contains(inner.getBounds())) {
1621 return;
1622 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001623
1624 this->onDrawDRRect(outer, inner, paint);
1625}
1626
reed41af9662015-01-05 07:49:08 -08001627void SkCanvas::drawPaint(const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001628 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001629 this->onDrawPaint(paint);
1630}
1631
1632void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001633 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001634 // To avoid redundant logic in our culling code and various backends, we always sort rects
1635 // before passing them along.
1636 this->onDrawRect(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001637}
1638
msarettdca352e2016-08-26 06:37:45 -07001639void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001640 TRACE_EVENT0("skia", TRACE_FUNC);
msarettdca352e2016-08-26 06:37:45 -07001641 if (region.isEmpty()) {
1642 return;
1643 }
1644
1645 if (region.isRect()) {
1646 return this->drawIRect(region.getBounds(), paint);
1647 }
1648
1649 this->onDrawRegion(region, paint);
1650}
1651
reed41af9662015-01-05 07:49:08 -08001652void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001653 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman6e3ce402017-05-17 15:10:18 -04001654 // To avoid redundant logic in our culling code and various backends, we always sort rects
1655 // before passing them along.
1656 this->onDrawOval(r.makeSorted(), paint);
reed41af9662015-01-05 07:49:08 -08001657}
1658
1659void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001660 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001661 this->onDrawRRect(rrect, paint);
1662}
1663
1664void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001665 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001666 this->onDrawPoints(mode, count, pts, paint);
1667}
1668
Mike Reede88a1cb2017-03-17 09:50:46 -04001669void SkCanvas::drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode,
1670 const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001671 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Salomon199fb872017-02-06 09:41:10 -05001672 RETURN_ON_NULL(vertices);
Mike Reede88a1cb2017-03-17 09:50:46 -04001673 this->onDrawVerticesObject(vertices.get(), mode, paint);
1674}
1675
1676void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001677 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reede88a1cb2017-03-17 09:50:46 -04001678 RETURN_ON_NULL(vertices);
1679 this->onDrawVerticesObject(vertices, mode, paint);
reed41af9662015-01-05 07:49:08 -08001680}
1681
1682void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001683 TRACE_EVENT0("skia", TRACE_FUNC);
reed41af9662015-01-05 07:49:08 -08001684 this->onDrawPath(path, paint);
1685}
1686
reeda85d4d02015-05-06 12:56:48 -07001687void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001688 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001689 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001690 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001691}
1692
Mike Reedc4e31092018-01-30 11:15:27 -05001693// Returns true if the rect can be "filled" : non-empty and finite
1694static bool fillable(const SkRect& r) {
1695 SkScalar w = r.width();
1696 SkScalar h = r.height();
1697 return SkScalarIsFinite(w) && w > 0 && SkScalarIsFinite(h) && h > 0;
1698}
1699
reede47829b2015-08-06 10:02:53 -07001700void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1701 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001702 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001703 RETURN_ON_NULL(image);
Mike Reedc4e31092018-01-30 11:15:27 -05001704 if (!fillable(dst) || !fillable(src)) {
reede47829b2015-08-06 10:02:53 -07001705 return;
1706 }
1707 this->onDrawImageRect(image, &src, dst, paint, constraint);
1708}
reed41af9662015-01-05 07:49:08 -08001709
reed84984ef2015-07-17 07:09:43 -07001710void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1711 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001712 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001713 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001714}
1715
reede47829b2015-08-06 10:02:53 -07001716void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1717 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001718 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001719 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1720 constraint);
1721}
reede47829b2015-08-06 10:02:53 -07001722
reed4c21dc52015-06-25 12:32:03 -07001723void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1724 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001725 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001726 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001727 if (dst.isEmpty()) {
1728 return;
1729 }
msarett552bca92016-08-03 06:53:26 -07001730 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1731 this->onDrawImageNine(image, center, dst, paint);
1732 } else {
reede47829b2015-08-06 10:02:53 -07001733 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001734 }
reed4c21dc52015-06-25 12:32:03 -07001735}
1736
msarett16882062016-08-16 09:31:08 -07001737void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1738 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001739 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001740 RETURN_ON_NULL(image);
1741 if (dst.isEmpty()) {
1742 return;
1743 }
msarett71df2d72016-09-30 12:41:42 -07001744
1745 SkIRect bounds;
1746 Lattice latticePlusBounds = lattice;
1747 if (!latticePlusBounds.fBounds) {
1748 bounds = SkIRect::MakeWH(image->width(), image->height());
1749 latticePlusBounds.fBounds = &bounds;
1750 }
1751
1752 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1753 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001754 } else {
1755 this->drawImageRect(image, dst, paint);
1756 }
1757}
1758
reed41af9662015-01-05 07:49:08 -08001759void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001760 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001761 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001762 return;
1763 }
reed41af9662015-01-05 07:49:08 -08001764 this->onDrawBitmap(bitmap, dx, dy, paint);
1765}
1766
reede47829b2015-08-06 10:02:53 -07001767void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001768 const SkPaint* paint, SrcRectConstraint constraint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001769 TRACE_EVENT0("skia", TRACE_FUNC);
reede47829b2015-08-06 10:02:53 -07001770 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001771 return;
1772 }
reede47829b2015-08-06 10:02:53 -07001773 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001774}
1775
reed84984ef2015-07-17 07:09:43 -07001776void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1777 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001778 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001779}
1780
reede47829b2015-08-06 10:02:53 -07001781void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1782 SrcRectConstraint constraint) {
1783 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1784 constraint);
1785}
reede47829b2015-08-06 10:02:53 -07001786
reed41af9662015-01-05 07:49:08 -08001787void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1788 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001789 TRACE_EVENT0("skia", TRACE_FUNC);
reed4c21dc52015-06-25 12:32:03 -07001790 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001791 return;
1792 }
msarett552bca92016-08-03 06:53:26 -07001793 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1794 this->onDrawBitmapNine(bitmap, center, dst, paint);
1795 } else {
reeda5517e22015-07-14 10:54:12 -07001796 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001797 }
reed41af9662015-01-05 07:49:08 -08001798}
1799
msarettc573a402016-08-02 08:05:56 -07001800void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1801 const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001802 TRACE_EVENT0("skia", TRACE_FUNC);
msarett16882062016-08-16 09:31:08 -07001803 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001804 return;
1805 }
msarett71df2d72016-09-30 12:41:42 -07001806
1807 SkIRect bounds;
1808 Lattice latticePlusBounds = lattice;
1809 if (!latticePlusBounds.fBounds) {
1810 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1811 latticePlusBounds.fBounds = &bounds;
1812 }
1813
1814 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1815 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001816 } else {
msarett16882062016-08-16 09:31:08 -07001817 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001818 }
msarettc573a402016-08-02 08:05:56 -07001819}
1820
reed71c3c762015-06-24 10:29:17 -07001821void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001822 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001823 const SkRect* cull, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001824 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08001825 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001826 if (count <= 0) {
1827 return;
1828 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001829 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001830 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001831 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001832}
1833
reedf70b5312016-03-04 16:36:20 -08001834void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001835 TRACE_EVENT0("skia", TRACE_FUNC);
reedf70b5312016-03-04 16:36:20 -08001836 if (key) {
1837 this->onDrawAnnotation(rect, key, value);
1838 }
1839}
1840
reede47829b2015-08-06 10:02:53 -07001841void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1842 const SkPaint* paint, SrcRectConstraint constraint) {
1843 if (src) {
1844 this->drawImageRect(image, *src, dst, paint, constraint);
1845 } else {
1846 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1847 dst, paint, constraint);
1848 }
1849}
1850void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1851 const SkPaint* paint, SrcRectConstraint constraint) {
1852 if (src) {
1853 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1854 } else {
1855 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1856 dst, paint, constraint);
1857 }
1858}
1859
Mike Reed4204da22017-05-17 08:53:36 -04001860void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
Brian Osman5e035ca2017-07-26 10:18:57 -04001861 TRACE_EVENT0("skia", TRACE_FUNC);
Mike Reed4204da22017-05-17 08:53:36 -04001862 this->onDrawShadowRec(path, rec);
1863}
1864
1865void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
1866 SkPaint paint;
1867 const SkRect& pathBounds = path.getBounds();
1868
1869 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
1870 while (iter.next()) {
1871 iter.fDevice->drawShadow(path, rec);
1872 }
1873 LOOPER_END
1874}
1875
reed@android.com8a1c16f2008-12-17 15:59:43 +00001876//////////////////////////////////////////////////////////////////////////////
1877// These are the virtual drawing methods
1878//////////////////////////////////////////////////////////////////////////////
1879
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001880void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001881 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001882 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1883 }
1884}
1885
reed41af9662015-01-05 07:49:08 -08001886void SkCanvas::onDrawPaint(const SkPaint& paint) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001887 this->internalDrawPaint(paint);
1888}
1889
1890void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001891 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001892
1893 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001894 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001895 }
1896
reed@google.com4e2b3d32011-04-07 14:18:59 +00001897 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001898}
1899
reed41af9662015-01-05 07:49:08 -08001900void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1901 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001902 if ((long)count <= 0) {
1903 return;
1904 }
1905
Mike Reed822128b2017-02-28 16:41:03 -05001906 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001907 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001908 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001909 // special-case 2 points (common for drawing a single line)
1910 if (2 == count) {
1911 r.set(pts[0], pts[1]);
1912 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001913 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001914 }
Jim Van Verth5d32b832018-02-21 11:14:32 -05001915 if (!r.isFinite()) {
1916 return;
1917 }
Mike Reed822128b2017-02-28 16:41:03 -05001918 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001919 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1920 return;
1921 }
1922 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001923 }
reed@google.coma584aed2012-05-16 14:06:02 +00001924
halcanary96fcdcc2015-08-27 07:41:13 -07001925 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001926
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001927 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001928
reed@android.com8a1c16f2008-12-17 15:59:43 +00001929 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001930 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001931 }
reed@google.com4b226022011-01-11 18:32:13 +00001932
reed@google.com4e2b3d32011-04-07 14:18:59 +00001933 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001934}
1935
reed4a167172016-08-18 17:15:25 -07001936static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
1937 return ((intptr_t)paint.getImageFilter() |
1938#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
1939 (intptr_t)canvas->getDrawFilter() |
1940#endif
1941 (intptr_t)paint.getLooper() ) != 0;
1942}
1943
reed41af9662015-01-05 07:49:08 -08001944void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001945 SkASSERT(r.isSorted());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001946 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001947 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001948 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001949 return;
1950 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001951 }
reed@google.com4b226022011-01-11 18:32:13 +00001952
reed4a167172016-08-18 17:15:25 -07001953 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05001954 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001955
reed4a167172016-08-18 17:15:25 -07001956 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001957 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07001958 }
1959
1960 LOOPER_END
1961 } else {
Mike Reed822128b2017-02-28 16:41:03 -05001962 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07001963 SkDrawIter iter(this);
1964 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001965 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07001966 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001967 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001968}
1969
msarett44df6512016-08-25 13:54:30 -07001970void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07001971 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07001972 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001973 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07001974 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
1975 return;
1976 }
msarett44df6512016-08-25 13:54:30 -07001977 }
1978
Mike Reed822128b2017-02-28 16:41:03 -05001979 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07001980
1981 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001982 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07001983 }
1984
1985 LOOPER_END
1986}
1987
reed41af9662015-01-05 07:49:08 -08001988void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04001989 SkASSERT(oval.isSorted());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001990 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05001991 SkRect storage;
Brian Osman6e3ce402017-05-17 15:10:18 -04001992 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07001993 return;
1994 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00001995 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001996
Mike Reed822128b2017-02-28 16:41:03 -05001997 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001998
1999 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002000 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002001 }
2002
2003 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002004}
2005
bsalomonac3aa242016-08-19 11:25:19 -07002006void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2007 SkScalar sweepAngle, bool useCenter,
2008 const SkPaint& paint) {
Brian Osman6e3ce402017-05-17 15:10:18 -04002009 SkASSERT(oval.isSorted());
bsalomonac3aa242016-08-19 11:25:19 -07002010 if (paint.canComputeFastBounds()) {
2011 SkRect storage;
2012 // Note we're using the entire oval as the bounds.
Brian Osman6e3ce402017-05-17 15:10:18 -04002013 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
bsalomonac3aa242016-08-19 11:25:19 -07002014 return;
2015 }
bsalomonac3aa242016-08-19 11:25:19 -07002016 }
2017
Mike Reed822128b2017-02-28 16:41:03 -05002018 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002019
2020 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002021 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002022 }
2023
2024 LOOPER_END
2025}
2026
reed41af9662015-01-05 07:49:08 -08002027void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002028 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002029 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002030 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2031 return;
2032 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002033 }
2034
2035 if (rrect.isRect()) {
2036 // call the non-virtual version
2037 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002038 return;
2039 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002040 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002041 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2042 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002043 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002044
Mike Reed822128b2017-02-28 16:41:03 -05002045 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002046
2047 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002048 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002049 }
2050
2051 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002052}
2053
Mike Reed822128b2017-02-28 16:41:03 -05002054void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002055 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002056 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002057 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2058 return;
2059 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002060 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002061
Mike Reed822128b2017-02-28 16:41:03 -05002062 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002063
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002064 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002065 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002066 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002067
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002068 LOOPER_END
2069}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002070
reed41af9662015-01-05 07:49:08 -08002071void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
reed@google.com93645112012-07-26 16:11:47 +00002072 if (!path.isFinite()) {
2073 return;
2074 }
2075
Mike Reed822128b2017-02-28 16:41:03 -05002076 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002077 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002078 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002079 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2080 return;
2081 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002082 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002083
Mike Reed822128b2017-02-28 16:41:03 -05002084 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002085 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002086 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002087 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002088 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002089 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002090
Mike Reed822128b2017-02-28 16:41:03 -05002091 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002092
2093 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002094 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002095 }
2096
reed@google.com4e2b3d32011-04-07 14:18:59 +00002097 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002098}
2099
reed262a71b2015-12-05 13:07:27 -08002100bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002101 if (!paint.getImageFilter()) {
2102 return false;
2103 }
2104
2105 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002106 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002107 return false;
2108 }
2109
2110 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2111 // Once we can filter and the filter will return a result larger than itself, we should be
2112 // able to remove this constraint.
2113 // skbug.com/4526
2114 //
2115 SkPoint pt;
2116 ctm.mapXY(x, y, &pt);
2117 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2118 return ir.contains(fMCRec->fRasterClip.getBounds());
2119}
2120
reeda85d4d02015-05-06 12:56:48 -07002121void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07002122 SkRect bounds = SkRect::MakeXYWH(x, y,
2123 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002124 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002125 SkRect tmp = bounds;
2126 if (paint) {
2127 paint->computeFastBounds(tmp, &tmp);
2128 }
2129 if (this->quickReject(tmp)) {
2130 return;
2131 }
reeda85d4d02015-05-06 12:56:48 -07002132 }
halcanary9d524f22016-03-29 09:03:52 -07002133
reeda85d4d02015-05-06 12:56:48 -07002134 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002135 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002136 paint = lazy.init();
2137 }
reed262a71b2015-12-05 13:07:27 -08002138
reeda2217ef2016-07-20 06:04:34 -07002139 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002140 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2141 *paint);
2142 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002143 special = this->getDevice()->makeSpecial(image);
2144 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002145 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002146 }
2147 }
2148
reed262a71b2015-12-05 13:07:27 -08002149 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2150
reeda85d4d02015-05-06 12:56:48 -07002151 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002152 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002153 if (special) {
2154 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002155 iter.fDevice->ctm().mapXY(x, y, &pt);
2156 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002157 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002158 SkScalarRoundToInt(pt.fY), pnt,
2159 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002160 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002161 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002162 }
reeda85d4d02015-05-06 12:56:48 -07002163 }
halcanary9d524f22016-03-29 09:03:52 -07002164
reeda85d4d02015-05-06 12:56:48 -07002165 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002166}
2167
reed41af9662015-01-05 07:49:08 -08002168void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002169 const SkPaint* paint, SrcRectConstraint constraint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002170 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002171 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002172 if (paint) {
2173 paint->computeFastBounds(dst, &storage);
2174 }
2175 if (this->quickReject(storage)) {
2176 return;
2177 }
reeda85d4d02015-05-06 12:56:48 -07002178 }
2179 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002180 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002181 paint = lazy.init();
2182 }
halcanary9d524f22016-03-29 09:03:52 -07002183
senorblancoc41e7e12015-12-07 12:51:30 -08002184 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002185 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002186
reeda85d4d02015-05-06 12:56:48 -07002187 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002188 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002189 }
halcanary9d524f22016-03-29 09:03:52 -07002190
reeda85d4d02015-05-06 12:56:48 -07002191 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002192}
2193
reed41af9662015-01-05 07:49:08 -08002194void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002195 SkDEBUGCODE(bitmap.validate();)
2196
reed33366972015-10-08 09:22:02 -07002197 if (bitmap.drawsNothing()) {
2198 return;
2199 }
2200
2201 SkLazyPaint lazy;
2202 if (nullptr == paint) {
2203 paint = lazy.init();
2204 }
2205
Mike Reed822128b2017-02-28 16:41:03 -05002206 SkRect bounds;
2207 bitmap.getBounds(&bounds);
2208 bounds.offset(x, y);
2209 bool canFastBounds = paint->canComputeFastBounds();
2210 if (canFastBounds) {
2211 SkRect storage;
2212 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002213 return;
2214 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002215 }
reed@google.com4b226022011-01-11 18:32:13 +00002216
reeda2217ef2016-07-20 06:04:34 -07002217 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002218 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2219 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002220 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002221 special = this->getDevice()->makeSpecial(bitmap);
2222 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002223 drawAsSprite = false;
2224 }
2225 }
2226
Mike Reed822128b2017-02-28 16:41:03 -05002227 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002228
2229 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002230 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002231 if (special) {
reed262a71b2015-12-05 13:07:27 -08002232 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002233 iter.fDevice->ctm().mapXY(x, y, &pt);
2234 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002235 SkScalarRoundToInt(pt.fX),
Florin Malita53f77bd2017-04-28 13:48:37 -04002236 SkScalarRoundToInt(pt.fY), pnt,
2237 nullptr, SkMatrix::I());
reed262a71b2015-12-05 13:07:27 -08002238 } else {
Hal Canaryb9642382017-06-27 09:58:56 -04002239 iter.fDevice->drawBitmap(bitmap, x, y, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002240 }
reed33366972015-10-08 09:22:02 -07002241 }
msarettfbfa2582016-08-12 08:29:08 -07002242
reed33366972015-10-08 09:22:02 -07002243 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002244}
2245
reed@google.com9987ec32011-09-07 11:57:52 +00002246// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002247void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002248 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002249 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002250 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002251 return;
2252 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002253
halcanary96fcdcc2015-08-27 07:41:13 -07002254 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002255 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002256 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2257 return;
2258 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002259 }
reed@google.com3d608122011-11-21 15:16:16 +00002260
reed@google.com33535f32012-09-25 15:37:50 +00002261 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002262 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002263 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002264 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002265
senorblancoc41e7e12015-12-07 12:51:30 -08002266 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002267 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002268
reed@google.com33535f32012-09-25 15:37:50 +00002269 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002270 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002271 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002272
reed@google.com33535f32012-09-25 15:37:50 +00002273 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002274}
2275
reed41af9662015-01-05 07:49:08 -08002276void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002277 const SkPaint* paint, SrcRectConstraint constraint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002278 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002279 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002280}
2281
reed4c21dc52015-06-25 12:32:03 -07002282void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2283 const SkPaint* paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002284 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002285 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002286 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2287 return;
2288 }
reed@google.com3d608122011-11-21 15:16:16 +00002289 }
halcanary9d524f22016-03-29 09:03:52 -07002290
reed4c21dc52015-06-25 12:32:03 -07002291 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002292 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002293 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002294 }
halcanary9d524f22016-03-29 09:03:52 -07002295
senorblancoc41e7e12015-12-07 12:51:30 -08002296 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002297
reed4c21dc52015-06-25 12:32:03 -07002298 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002299 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002300 }
halcanary9d524f22016-03-29 09:03:52 -07002301
reed4c21dc52015-06-25 12:32:03 -07002302 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002303}
2304
reed41af9662015-01-05 07:49:08 -08002305void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2306 const SkPaint* paint) {
reed@google.com9987ec32011-09-07 11:57:52 +00002307 SkDEBUGCODE(bitmap.validate();)
2308
halcanary96fcdcc2015-08-27 07:41:13 -07002309 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002310 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002311 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2312 return;
2313 }
reed4c21dc52015-06-25 12:32:03 -07002314 }
halcanary9d524f22016-03-29 09:03:52 -07002315
reed4c21dc52015-06-25 12:32:03 -07002316 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002317 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002318 paint = lazy.init();
2319 }
halcanary9d524f22016-03-29 09:03:52 -07002320
senorblancoc41e7e12015-12-07 12:51:30 -08002321 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002322
reed4c21dc52015-06-25 12:32:03 -07002323 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002324 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002325 }
halcanary9d524f22016-03-29 09:03:52 -07002326
reed4c21dc52015-06-25 12:32:03 -07002327 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002328}
2329
msarett16882062016-08-16 09:31:08 -07002330void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2331 const SkPaint* paint) {
2332 if (nullptr == paint || paint->canComputeFastBounds()) {
2333 SkRect storage;
2334 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2335 return;
2336 }
2337 }
2338
2339 SkLazyPaint lazy;
2340 if (nullptr == paint) {
2341 paint = lazy.init();
2342 }
2343
2344 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2345
2346 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002347 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002348 }
2349
2350 LOOPER_END
2351}
2352
2353void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2354 const SkRect& dst, const SkPaint* paint) {
2355 if (nullptr == paint || paint->canComputeFastBounds()) {
2356 SkRect storage;
2357 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2358 return;
2359 }
2360 }
2361
2362 SkLazyPaint lazy;
2363 if (nullptr == paint) {
2364 paint = lazy.init();
2365 }
2366
2367 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2368
2369 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002370 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002371 }
2372
2373 LOOPER_END
2374}
2375
reed@google.comf67e4cf2011-03-15 20:56:58 +00002376class SkDeviceFilteredPaint {
2377public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002378 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002379 uint32_t filteredFlags = device->filterTextFlags(paint);
2380 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002381 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002382 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002383 fPaint = newPaint;
2384 } else {
2385 fPaint = &paint;
2386 }
2387 }
2388
reed@google.comf67e4cf2011-03-15 20:56:58 +00002389 const SkPaint& paint() const { return *fPaint; }
2390
2391private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002392 const SkPaint* fPaint;
2393 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002394};
2395
reed@google.come0d9ce82014-04-23 04:00:17 +00002396void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2397 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002398 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002399
2400 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002401 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002402 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002403 }
2404
reed@google.com4e2b3d32011-04-07 14:18:59 +00002405 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002406}
2407
reed@google.come0d9ce82014-04-23 04:00:17 +00002408void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2409 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002410 SkPoint textOffset = SkPoint::Make(0, 0);
2411
halcanary96fcdcc2015-08-27 07:41:13 -07002412 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002413
reed@android.com8a1c16f2008-12-17 15:59:43 +00002414 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002415 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002416 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002417 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002418 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002419
reed@google.com4e2b3d32011-04-07 14:18:59 +00002420 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002421}
2422
reed@google.come0d9ce82014-04-23 04:00:17 +00002423void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2424 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002425
2426 SkPoint textOffset = SkPoint::Make(0, constY);
2427
halcanary96fcdcc2015-08-27 07:41:13 -07002428 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002429
reed@android.com8a1c16f2008-12-17 15:59:43 +00002430 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002431 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002432 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002433 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002434 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002435
reed@google.com4e2b3d32011-04-07 14:18:59 +00002436 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002437}
2438
reed@google.come0d9ce82014-04-23 04:00:17 +00002439void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2440 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002441 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002442
reed@android.com8a1c16f2008-12-17 15:59:43 +00002443 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002444 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002445 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002446 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002447
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002448 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002449}
2450
reed45561a02016-07-07 12:47:17 -07002451void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2452 const SkRect* cullRect, const SkPaint& paint) {
2453 if (cullRect && this->quickReject(*cullRect)) {
2454 return;
2455 }
2456
2457 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2458
2459 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002460 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002461 }
2462
2463 LOOPER_END
2464}
2465
fmalita00d5c2c2014-08-21 08:53:26 -07002466void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2467 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002468
fmalita85d5eb92015-03-04 11:20:12 -08002469 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002470 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002471 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002472 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002473 SkRect tmp;
2474 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2475 return;
2476 }
2477 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002478 }
2479
fmalita024f9962015-03-03 19:08:17 -08002480 // We cannot filter in the looper as we normally do, because the paint is
2481 // incomplete at this point (text-related attributes are embedded within blob run paints).
2482 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002483 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002484
fmalita85d5eb92015-03-04 11:20:12 -08002485 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002486
fmalitaaa1b9122014-08-28 14:32:24 -07002487 while (iter.next()) {
2488 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002489 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002490 }
2491
fmalitaaa1b9122014-08-28 14:32:24 -07002492 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002493
2494 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002495}
2496
Cary Clark2a475ea2017-04-28 15:35:12 -04002497void SkCanvas::drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint) {
2498 this->drawText(string.c_str(), string.size(), x, y, paint);
2499}
2500
reed@google.come0d9ce82014-04-23 04:00:17 +00002501// These will become non-virtual, so they always call the (virtual) onDraw... method
2502void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2503 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002504 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002505 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002506 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002507 this->onDrawText(text, byteLength, x, y, paint);
2508 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002509}
2510void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2511 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002512 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002513 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002514 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002515 this->onDrawPosText(text, byteLength, pos, paint);
2516 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002517}
2518void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2519 SkScalar constY, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002520 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002521 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002522 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002523 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2524 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002525}
2526void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2527 const SkMatrix* matrix, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002528 TRACE_EVENT0("skia", TRACE_FUNC);
reedac095542016-08-04 15:54:41 -07002529 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002530 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reedac095542016-08-04 15:54:41 -07002531 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2532 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002533}
reed45561a02016-07-07 12:47:17 -07002534void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2535 const SkRect* cullRect, const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002536 TRACE_EVENT0("skia", TRACE_FUNC);
reed45561a02016-07-07 12:47:17 -07002537 if (byteLength) {
Ben Wagner4bd3b092017-08-01 13:22:23 -04002538 sk_msan_assert_initialized(text, SkTAddOffset<const void>(text, byteLength));
reed45561a02016-07-07 12:47:17 -07002539 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2540 }
2541}
fmalita00d5c2c2014-08-21 08:53:26 -07002542void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2543 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002544 TRACE_EVENT0("skia", TRACE_FUNC);
Brian Osman5e035ca2017-07-26 10:18:57 -04002545 RETURN_ON_NULL(blob);
Mike Reed74d6e112018-01-23 13:06:12 -05002546 RETURN_ON_FALSE(blob->bounds().makeOffset(x, y).isFinite());
reede3b38ce2016-01-08 09:18:44 -08002547 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002548}
reed@google.come0d9ce82014-04-23 04:00:17 +00002549
Mike Reede88a1cb2017-03-17 09:50:46 -04002550void SkCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
2551 const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05002552 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2553
2554 while (iter.next()) {
2555 // In the common case of one iteration we could std::move vertices here.
Mike Reed2f6b5a42017-03-19 15:04:17 -04002556 iter.fDevice->drawVertices(vertices, bmode, looper.paint());
Brian Salomon199fb872017-02-06 09:41:10 -05002557 }
2558
2559 LOOPER_END
2560}
2561
dandovb3c9d1c2014-08-12 08:34:29 -07002562void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002563 const SkPoint texCoords[4], SkBlendMode bmode,
2564 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002565 TRACE_EVENT0("skia", TRACE_FUNC);
halcanary96fcdcc2015-08-27 07:41:13 -07002566 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002567 return;
2568 }
mtklein6cfa73a2014-08-13 13:33:49 -07002569
Mike Reedfaba3712016-11-03 14:45:31 -04002570 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002571}
2572
2573void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002574 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002575 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002576 // Since a patch is always within the convex hull of the control points, we discard it when its
2577 // bounding rectangle is completely outside the current clip.
2578 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002579 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002580 if (this->quickReject(bounds)) {
2581 return;
2582 }
mtklein6cfa73a2014-08-13 13:33:49 -07002583
Mike Reed435071e2017-05-23 11:22:56 -04002584 const bool interpColorsLinearly = (this->imageInfo().colorSpace() != nullptr);
2585
halcanary96fcdcc2015-08-27 07:41:13 -07002586 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002587
dandovecfff212014-08-04 10:02:00 -07002588 while (iter.next()) {
Mike Reed435071e2017-05-23 11:22:56 -04002589 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, interpColorsLinearly, paint);
dandovecfff212014-08-04 10:02:00 -07002590 }
mtklein6cfa73a2014-08-13 13:33:49 -07002591
dandovecfff212014-08-04 10:02:00 -07002592 LOOPER_END
2593}
2594
reeda8db7282015-07-07 10:22:31 -07002595void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002596#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002597 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002598#endif
reede3b38ce2016-01-08 09:18:44 -08002599 RETURN_ON_NULL(dr);
2600 if (x || y) {
2601 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2602 this->onDrawDrawable(dr, &matrix);
2603 } else {
2604 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002605 }
2606}
2607
reeda8db7282015-07-07 10:22:31 -07002608void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002609#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
Brian Osman5e035ca2017-07-26 10:18:57 -04002610 TRACE_EVENT0("skia", TRACE_FUNC);
Derek Sollenbergeredf3dc02017-08-16 10:35:28 -04002611#endif
reede3b38ce2016-01-08 09:18:44 -08002612 RETURN_ON_NULL(dr);
2613 if (matrix && matrix->isIdentity()) {
2614 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002615 }
reede3b38ce2016-01-08 09:18:44 -08002616 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002617}
2618
2619void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002620 // drawable bounds are no longer reliable (e.g. android displaylist)
2621 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002622 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002623}
2624
reed71c3c762015-06-24 10:29:17 -07002625void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002626 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002627 const SkRect* cull, const SkPaint* paint) {
2628 if (cull && this->quickReject(*cull)) {
2629 return;
2630 }
2631
2632 SkPaint pnt;
2633 if (paint) {
2634 pnt = *paint;
2635 }
halcanary9d524f22016-03-29 09:03:52 -07002636
halcanary96fcdcc2015-08-27 07:41:13 -07002637 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002638 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002639 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002640 }
2641 LOOPER_END
2642}
2643
reedf70b5312016-03-04 16:36:20 -08002644void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2645 SkASSERT(key);
2646
2647 SkPaint paint;
2648 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2649 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002650 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002651 }
2652 LOOPER_END
2653}
2654
reed@android.com8a1c16f2008-12-17 15:59:43 +00002655//////////////////////////////////////////////////////////////////////////////
2656// These methods are NOT virtual, and therefore must call back into virtual
2657// methods, rather than actually drawing themselves.
2658//////////////////////////////////////////////////////////////////////////////
2659
reed374772b2016-10-05 17:33:02 -07002660void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002661 SkPaint paint;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002662 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002663 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002664 this->drawPaint(paint);
2665}
2666
2667void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
Mike Reed3661bc92017-02-22 13:21:42 -05002668 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002669 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2670}
2671
Mike Reed3661bc92017-02-22 13:21:42 -05002672void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002673 SkPoint pts[2];
reed@android.com8a1c16f2008-12-17 15:59:43 +00002674 pts[0].set(x0, y0);
2675 pts[1].set(x1, y1);
2676 this->drawPoints(kLines_PointMode, 2, pts, paint);
2677}
2678
Mike Reed3661bc92017-02-22 13:21:42 -05002679void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002680 if (radius < 0) {
2681 radius = 0;
2682 }
2683
2684 SkRect r;
2685 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002686 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002687}
2688
2689void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2690 const SkPaint& paint) {
2691 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002692 SkRRect rrect;
2693 rrect.setRectXY(r, rx, ry);
2694 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002695 } else {
2696 this->drawRect(r, paint);
2697 }
2698}
2699
reed@android.com8a1c16f2008-12-17 15:59:43 +00002700void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2701 SkScalar sweepAngle, bool useCenter,
2702 const SkPaint& paint) {
Brian Osman39c08ac2017-07-26 09:36:09 -04002703 TRACE_EVENT0("skia", TRACE_FUNC);
bsalomon21af9ca2016-08-25 12:29:23 -07002704 if (oval.isEmpty() || !sweepAngle) {
2705 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002706 }
bsalomon21af9ca2016-08-25 12:29:23 -07002707 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002708}
2709
2710void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2711 const SkPath& path, SkScalar hOffset,
2712 SkScalar vOffset, const SkPaint& paint) {
2713 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002714
reed@android.com8a1c16f2008-12-17 15:59:43 +00002715 matrix.setTranslate(hOffset, vOffset);
2716 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2717}
2718
reed@android.comf76bacf2009-05-13 14:00:33 +00002719///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002720
Mike Klein88d90712018-01-27 17:30:04 +00002721/**
2722 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2723 * against the playback cost of recursing into the subpicture to get at its actual ops.
2724 *
2725 * For now we pick a conservatively small value, though measurement (and other heuristics like
2726 * the type of ops contained) may justify changing this value.
2727 */
2728#define kMaxPictureOpsToUnrollInsteadOfRef 1
2729
reedd5fa1a42014-08-09 11:08:05 -07002730void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
Brian Osman5e035ca2017-07-26 10:18:57 -04002731 TRACE_EVENT0("skia", TRACE_FUNC);
reede3b38ce2016-01-08 09:18:44 -08002732 RETURN_ON_NULL(picture);
2733
reede3b38ce2016-01-08 09:18:44 -08002734 if (matrix && matrix->isIdentity()) {
2735 matrix = nullptr;
2736 }
Mike Klein88d90712018-01-27 17:30:04 +00002737 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2738 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2739 picture->playback(this);
2740 } else {
2741 this->onDrawPicture(picture, matrix, paint);
2742 }
reedd5fa1a42014-08-09 11:08:05 -07002743}
robertphillips9b14f262014-06-04 05:40:44 -07002744
reedd5fa1a42014-08-09 11:08:05 -07002745void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2746 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002747 if (!paint || paint->canComputeFastBounds()) {
2748 SkRect bounds = picture->cullRect();
2749 if (paint) {
2750 paint->computeFastBounds(bounds, &bounds);
2751 }
2752 if (matrix) {
2753 matrix->mapRect(&bounds);
2754 }
2755 if (this->quickReject(bounds)) {
2756 return;
2757 }
2758 }
2759
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002760 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002761 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762}
2763
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764///////////////////////////////////////////////////////////////////////////////
2765///////////////////////////////////////////////////////////////////////////////
2766
reed3aafe112016-08-18 12:45:34 -07002767SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07002768 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769
2770 SkASSERT(canvas);
2771
reed3aafe112016-08-18 12:45:34 -07002772 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002773 fDone = !fImpl->next();
2774}
2775
2776SkCanvas::LayerIter::~LayerIter() {
2777 fImpl->~SkDrawIter();
2778}
2779
2780void SkCanvas::LayerIter::next() {
2781 fDone = !fImpl->next();
2782}
2783
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002784SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05002785 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786}
2787
2788const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05002789 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790}
2791
2792const SkPaint& SkCanvas::LayerIter::paint() const {
2793 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002794 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795 paint = &fDefaultPaint;
2796 }
2797 return *paint;
2798}
2799
Mike Reeda1361362017-03-07 09:37:29 -05002800void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
2801 return fImpl->fDevice->onAsRgnClip(rgn);
2802}
2803
reed@android.com8a1c16f2008-12-17 15:59:43 +00002804int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2805int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002806
2807///////////////////////////////////////////////////////////////////////////////
2808
Brian Osman10fc6fd2018-03-02 11:01:10 -05002809// TODO: This still disagrees with SkSurfaceValidateRasterInfo
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002810static bool supported_for_raster_canvas(const SkImageInfo& info) {
2811 switch (info.alphaType()) {
2812 case kPremul_SkAlphaType:
2813 case kOpaque_SkAlphaType:
2814 break;
2815 default:
2816 return false;
2817 }
2818
2819 switch (info.colorType()) {
2820 case kAlpha_8_SkColorType:
2821 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002822 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07002823 case kRGBA_F16_SkColorType:
Brian Osman10fc6fd2018-03-02 11:01:10 -05002824 case kRGBA_1010102_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002825 break;
2826 default:
2827 return false;
2828 }
2829
2830 return true;
2831}
2832
Mike Reed5df49342016-11-12 08:06:55 -06002833std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
Mike Reed12f77342017-11-08 11:19:52 -05002834 size_t rowBytes, const SkSurfaceProps* props) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002835 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002836 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002837 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002838
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002839 SkBitmap bitmap;
2840 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002841 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002842 }
Mike Reed12f77342017-11-08 11:19:52 -05002843
2844 return props ?
2845 skstd::make_unique<SkCanvas>(bitmap, *props) :
2846 skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002847}
reedd5fa1a42014-08-09 11:08:05 -07002848
2849///////////////////////////////////////////////////////////////////////////////
2850
Florin Malitaee424ac2016-12-01 12:47:59 -05002851SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
2852 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
2853
Florin Malita439ace92016-12-02 12:05:41 -05002854SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
2855 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
2856
Herb Derby76d69b42018-03-15 17:34:40 -04002857SkNoDrawCanvas::SkNoDrawCanvas(SkBaseDevice *device)
2858 : INHERITED(device) {}
2859
Florin Malitaee424ac2016-12-01 12:47:59 -05002860SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
2861 (void)this->INHERITED::getSaveLayerStrategy(rec);
2862 return kNoLayer_SaveLayerStrategy;
2863}
2864
2865///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07002866
reed73603f32016-09-20 08:42:38 -07002867static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
2868static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
2869static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
2870static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
2871static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
2872static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05002873
2874///////////////////////////////////////////////////////////////////////////////////////////////////
2875
2876SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
2877 if (fAllocator && fMCRec->fTopLayer->fDevice) {
Florin Malita713b8ef2017-04-28 10:57:24 -04002878 const auto& dev = fMCRec->fTopLayer->fDevice;
Mike Reed356f7c22017-01-10 11:58:39 -05002879 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
2880 SkIPoint origin = dev->getOrigin();
2881 SkMatrix ctm = this->getTotalMatrix();
2882 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
2883
2884 SkIRect clip = fMCRec->fRasterClip.getBounds();
2885 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05002886 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05002887 clip.setEmpty();
2888 }
2889
2890 fAllocator->updateHandle(handle, ctm, clip);
2891 return handle;
2892 }
2893 return nullptr;
2894}
2895
2896static bool install(SkBitmap* bm, const SkImageInfo& info,
2897 const SkRasterHandleAllocator::Rec& rec) {
Mike Reed086a4272017-07-18 10:53:11 -04002898 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, rec.fReleaseProc, rec.fReleaseCtx);
Mike Reed356f7c22017-01-10 11:58:39 -05002899}
2900
2901SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
2902 SkBitmap* bm) {
2903 SkRasterHandleAllocator::Rec rec;
2904 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
2905 return nullptr;
2906 }
2907 return rec.fHandle;
2908}
2909
2910std::unique_ptr<SkCanvas>
2911SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
2912 const SkImageInfo& info, const Rec* rec) {
2913 if (!alloc || !supported_for_raster_canvas(info)) {
2914 return nullptr;
2915 }
2916
2917 SkBitmap bm;
2918 Handle hndl;
2919
2920 if (rec) {
2921 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
2922 } else {
2923 hndl = alloc->allocBitmap(info, &bm);
2924 }
2925 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
2926}
Mike Reed7c9c9e42018-01-03 09:23:34 -05002927
2928///////////////////////////////////////////////////////////////////////////////////////////////////
2929
2930