blob: daefeeb45a2642dd7a81afe1be027c55089d0570 [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"
Florin Malitaee424ac2016-12-01 12:47:59 -050026#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070027#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070028#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070029#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000030#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070031#include "SkRadialShadowMapShader.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"
vjiaoblack904527d2016-08-09 09:32:09 -070035#include "SkShadowPaintFilterCanvas.h"
36#include "SkShadowShader.h"
robertphillips4418dba2016-03-07 12:45:14 -080037#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000038#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070039#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000040#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000041#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080042#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070043#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080046#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000047#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070048#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050051#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050052#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053
reede3b38ce2016-01-08 09:18:44 -080054#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
55
reedc83a2972015-07-16 07:40:45 -070056/*
57 * Return true if the drawing this rect would hit every pixels in the canvas.
58 *
59 * Returns false if
60 * - rect does not contain the canvas' bounds
61 * - paint is not fill
62 * - paint would blur or otherwise change the coverage of the rect
63 */
64bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
65 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070066 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
67 (int)kNone_ShaderOverrideOpacity,
68 "need_matching_enums0");
69 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
70 (int)kOpaque_ShaderOverrideOpacity,
71 "need_matching_enums1");
72 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
73 (int)kNotOpaque_ShaderOverrideOpacity,
74 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070075
76 const SkISize size = this->getBaseLayerSize();
77 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
Mike Reeda1361362017-03-07 09:37:29 -050078
79 // if we're clipped at all, we can't overwrite the entire surface
80 {
81 SkBaseDevice* base = this->getDevice();
82 SkBaseDevice* top = this->getTopDevice();
83 if (base != top) {
84 return false; // we're in a saveLayer, so conservatively don't assume we'll overwrite
85 }
86 if (!base->clipIsWideOpen()) {
87 return false;
88 }
reedc83a2972015-07-16 07:40:45 -070089 }
90
91 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070092 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070093 return false; // conservative
94 }
halcanaryc5769b22016-08-10 07:13:21 -070095
96 SkRect devRect;
97 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
98 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070099 return false;
100 }
101 }
102
103 if (paint) {
104 SkPaint::Style paintStyle = paint->getStyle();
105 if (!(paintStyle == SkPaint::kFill_Style ||
106 paintStyle == SkPaint::kStrokeAndFill_Style)) {
107 return false;
108 }
109 if (paint->getMaskFilter() || paint->getLooper()
110 || paint->getPathEffect() || paint->getImageFilter()) {
111 return false; // conservative
112 }
113 }
114 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
115}
116
117///////////////////////////////////////////////////////////////////////////////////////////////////
118
reedd990e2f2014-12-22 11:58:30 -0800119static bool gIgnoreSaveLayerBounds;
120void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
121 gIgnoreSaveLayerBounds = ignore;
122}
123bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
124 return gIgnoreSaveLayerBounds;
125}
126
reed0acf1b42014-12-22 16:12:38 -0800127static bool gTreatSpriteAsBitmap;
128void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
129 gTreatSpriteAsBitmap = spriteAsBitmap;
130}
131bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
132 return gTreatSpriteAsBitmap;
133}
134
reed@google.comda17f752012-08-16 18:27:05 +0000135// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136//#define SK_TRACE_SAVERESTORE
137
138#ifdef SK_TRACE_SAVERESTORE
139 static int gLayerCounter;
140 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
141 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
142
143 static int gRecCounter;
144 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
145 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
146
147 static int gCanvasCounter;
148 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
149 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
150#else
151 #define inc_layer()
152 #define dec_layer()
153 #define inc_rec()
154 #define dec_rec()
155 #define inc_canvas()
156 #define dec_canvas()
157#endif
158
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000159typedef SkTLazy<SkPaint> SkLazyPaint;
160
reedc83a2972015-07-16 07:40:45 -0700161void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000162 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700163 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
164 ? SkSurface::kDiscard_ContentChangeMode
165 : SkSurface::kRetain_ContentChangeMode);
166 }
167}
168
169void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
170 ShaderOverrideOpacity overrideOpacity) {
171 if (fSurfaceBase) {
172 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
173 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
174 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
175 // and therefore we don't care which mode we're in.
176 //
177 if (fSurfaceBase->outstandingImageSnapshot()) {
178 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
179 mode = SkSurface::kDiscard_ContentChangeMode;
180 }
181 }
182 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000183 }
184}
185
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000188/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 The clip/matrix/proc are fields that reflect the top of the save/restore
190 stack. Whenever the canvas changes, it marks a dirty flag, and then before
191 these are used (assuming we're not on a layer) we rebuild these cache
192 values: they reflect the top of the save stack, but translated and clipped
193 by the device's XY offset and bitmap-bounds.
194*/
195struct DeviceCM {
196 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000197 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000198 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000199 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700200 const SkMatrix* fMatrix;
201 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700202 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203
Mike Reeda1361362017-03-07 09:37:29 -0500204 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700205 : fNext(nullptr)
reed8c30a812016-04-20 16:36:51 -0700206 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700207 {
reed2c9e2002016-07-25 08:05:22 -0700208 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000209 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700210 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000211 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000213 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700214 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700215 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000216 }
reed@google.com4b226022011-01-11 18:32:13 +0000217
mtkleinfeaadee2015-04-08 11:25:48 -0700218 void reset(const SkIRect& bounds) {
219 SkASSERT(!fPaint);
220 SkASSERT(!fNext);
221 SkASSERT(fDevice);
222 fClip.setRect(bounds);
223 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224};
225
226/* This is the record we keep for each save/restore level in the stack.
227 Since a level optionally copies the matrix and/or stack, we have pointers
228 for these fields. If the value is copied for this level, the copy is
229 stored in the ...Storage field, and the pointer points to that. If the
230 value is not copied for this level, we ignore ...Storage, and just point
231 at the corresponding value in the previous level in the stack.
232*/
233class SkCanvas::MCRec {
234public:
reed1f836ee2014-07-07 07:49:34 -0700235 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700236 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 /* If there are any layers in the stack, this points to the top-most
238 one that is at or below this level in the stack (so we know what
239 bitmap/device to draw into from this level. This value is NOT
240 reference counted, since the real owner is either our fLayer field,
241 or a previous one in a lower level.)
242 */
Mike Reeda1361362017-03-07 09:37:29 -0500243 DeviceCM* fTopLayer;
244 SkConservativeClip fRasterClip;
245 SkMatrix fMatrix;
246 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247
vjiaoblacke5de1302016-07-13 14:05:28 -0700248 // This is the current cumulative depth (aggregate of all done translateZ calls)
249 SkScalar fCurDrawDepth;
250
Mike Reeda1361362017-03-07 09:37:29 -0500251 MCRec() {
halcanary96fcdcc2015-08-27 07:41:13 -0700252 fFilter = nullptr;
253 fLayer = nullptr;
254 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800255 fMatrix.reset();
256 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700257 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700258
reedd9544982014-09-09 18:46:22 -0700259 // don't bother initializing fNext
260 inc_rec();
261 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700262 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
263 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700264 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700265 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700266 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800267 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700268
reed@android.com8a1c16f2008-12-17 15:59:43 +0000269 // don't bother initializing fNext
270 inc_rec();
271 }
272 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000273 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700274 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 dec_rec();
276 }
mtkleinfeaadee2015-04-08 11:25:48 -0700277
278 void reset(const SkIRect& bounds) {
279 SkASSERT(fLayer);
280 SkASSERT(fDeferredSaveCount == 0);
281
282 fMatrix.reset();
283 fRasterClip.setRect(bounds);
284 fLayer->reset(bounds);
285 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000286};
287
Mike Reeda1361362017-03-07 09:37:29 -0500288class SkDrawIter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289public:
Mike Reeda1361362017-03-07 09:37:29 -0500290 SkDrawIter(SkCanvas* canvas)
291 : fDevice(nullptr), fCurrLayer(canvas->fMCRec->fTopLayer), fPaint(nullptr)
292 {}
reed@google.com4b226022011-01-11 18:32:13 +0000293
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 bool next() {
reed@google.comf68c5e22012-02-24 16:38:58 +0000295 const DeviceCM* rec = fCurrLayer;
296 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 fDevice = rec->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298 fPaint = rec->fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700300 // fCurrLayer may be nullptr now
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301 return true;
302 }
303 return false;
304 }
reed@google.com4b226022011-01-11 18:32:13 +0000305
reed@google.com6f8f2922011-03-04 22:27:10 +0000306 int getX() const { return fDevice->getOrigin().x(); }
307 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000308 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000309
Mike Reed99330ba2017-02-22 11:01:08 -0500310 SkBaseDevice* fDevice;
311
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 const DeviceCM* fCurrLayer;
314 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315};
316
Mike Reed7627fa52017-02-08 10:07:53 -0500317#define FOR_EACH_TOP_DEVICE( code ) \
318 do { \
319 DeviceCM* layer = fMCRec->fTopLayer; \
320 while (layer) { \
321 SkBaseDevice* device = layer->fDevice; \
Mike Reedc42a1cd2017-02-14 14:25:14 -0500322 if (device) { \
323 code; \
324 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500325 layer = layer->fNext; \
326 } \
327 } while (0)
328
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329/////////////////////////////////////////////////////////////////////////////
330
reeddbc3cef2015-04-29 12:18:57 -0700331static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
332 return lazy->isValid() ? lazy->get() : lazy->set(orig);
333}
334
335/**
336 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700337 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700338 */
reedd053ce92016-03-22 10:17:23 -0700339static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700340 SkImageFilter* imgf = paint.getImageFilter();
341 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700342 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700343 }
344
reedd053ce92016-03-22 10:17:23 -0700345 SkColorFilter* imgCFPtr;
346 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700347 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700348 }
reedd053ce92016-03-22 10:17:23 -0700349 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700350
351 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700352 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700353 // there is no existing paint colorfilter, so we can just return the imagefilter's
354 return imgCF;
355 }
356
357 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
358 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700359 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700360}
361
senorblanco87e066e2015-10-28 11:23:36 -0700362/**
363 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
364 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
365 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
366 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
367 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
368 * conservative "effective" bounds based on the settings in the paint... with one exception. This
369 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
370 * deliberately ignored.
371 */
372static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
373 const SkRect& rawBounds,
374 SkRect* storage) {
375 SkPaint tmpUnfiltered(paint);
376 tmpUnfiltered.setImageFilter(nullptr);
377 if (tmpUnfiltered.canComputeFastBounds()) {
378 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
379 } else {
380 return rawBounds;
381 }
382}
383
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384class AutoDrawLooper {
385public:
senorblanco87e066e2015-10-28 11:23:36 -0700386 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
387 // paint. It's used to determine the size of the offscreen layer for filters.
388 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700389 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700390 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000391 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800392#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000393 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800394#else
395 fFilter = nullptr;
396#endif
reed4a8126e2014-09-22 07:29:03 -0700397 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000398 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700399 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000400 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401
reedd053ce92016-03-22 10:17:23 -0700402 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700403 if (simplifiedCF) {
404 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700405 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700406 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700407 fPaint = paint;
408 }
409
410 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700411 /**
412 * We implement ImageFilters for a given draw by creating a layer, then applying the
413 * imagefilter to the pixels of that layer (its backing surface/image), and then
414 * we call restore() to xfer that layer to the main canvas.
415 *
416 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
417 * 2. Generate the src pixels:
418 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
419 * return (fPaint). We then draw the primitive (using srcover) into a cleared
420 * buffer/surface.
421 * 3. Restore the layer created in #1
422 * The imagefilter is passed the buffer/surface from the layer (now filled with the
423 * src pixels of the primitive). It returns a new "filtered" buffer, which we
424 * draw onto the previous layer using the xfermode from the original paint.
425 */
reed@google.com8926b162012-03-23 15:36:36 +0000426 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500427 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700428 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700429 SkRect storage;
430 if (rawBounds) {
431 // Make rawBounds include all paint outsets except for those due to image filters.
432 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
433 }
reedbfd5f172016-01-07 11:28:08 -0800434 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700435 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700436 fTempLayerForImageFilter = true;
437 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000438 }
439
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000440 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500441 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000442 fIsSimple = false;
443 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700444 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000445 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700446 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000447 }
448 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000449
reed@android.com8a1c16f2008-12-17 15:59:43 +0000450 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700451 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000452 fCanvas->internalRestore();
453 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000454 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000455 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000456
reed@google.com4e2b3d32011-04-07 14:18:59 +0000457 const SkPaint& paint() const {
458 SkASSERT(fPaint);
459 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000461
reed@google.com129ec222012-05-15 13:24:09 +0000462 bool next(SkDrawFilter::Type drawType) {
463 if (fDone) {
464 return false;
465 } else if (fIsSimple) {
466 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000467 return !fPaint->nothingToDraw();
468 } else {
469 return this->doNext(drawType);
470 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000471 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000472
reed@android.com8a1c16f2008-12-17 15:59:43 +0000473private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500474 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700475 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000476 SkCanvas* fCanvas;
477 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000478 SkDrawFilter* fFilter;
479 const SkPaint* fPaint;
480 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700481 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000482 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000483 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000484 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500485 char fStorage[48];
486 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000487
488 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000489};
490
reed@google.com129ec222012-05-15 13:24:09 +0000491bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700492 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000493 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700494 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000495
reeddbc3cef2015-04-29 12:18:57 -0700496 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
497 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000498
reed5c476fb2015-04-20 08:04:21 -0700499 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700500 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700501 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000502 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000503
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000504 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000505 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000506 return false;
507 }
508 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000509 if (!fFilter->filter(paint, drawType)) {
510 fDone = true;
511 return false;
512 }
halcanary96fcdcc2015-08-27 07:41:13 -0700513 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000514 // no looper means we only draw once
515 fDone = true;
516 }
517 }
518 fPaint = paint;
519
520 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000521 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000522 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000523 }
524
525 // call this after any possible paint modifiers
526 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700527 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000528 return false;
529 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000530 return true;
531}
532
reed@android.com8a1c16f2008-12-17 15:59:43 +0000533////////// macros to place around the internal draw calls //////////////////
534
reed3aafe112016-08-18 12:45:34 -0700535#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
536 this->predrawNotify(); \
537 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
538 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800539 SkDrawIter iter(this);
540
541
reed@google.com8926b162012-03-23 15:36:36 +0000542#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000543 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700544 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000545 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000546 SkDrawIter iter(this);
547
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000548#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000549 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700550 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000551 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000553
reedc83a2972015-07-16 07:40:45 -0700554#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
555 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700556 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700557 while (looper.next(type)) { \
558 SkDrawIter iter(this);
559
reed@google.com4e2b3d32011-04-07 14:18:59 +0000560#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000561
562////////////////////////////////////////////////////////////////////////////
563
msarettfbfa2582016-08-12 08:29:08 -0700564static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
565 if (bounds.isEmpty()) {
566 return SkRect::MakeEmpty();
567 }
568
569 // Expand bounds out by 1 in case we are anti-aliasing. We store the
570 // bounds as floats to enable a faster quick reject implementation.
571 SkRect dst;
572 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
573 return dst;
574}
575
mtkleinfeaadee2015-04-08 11:25:48 -0700576void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
577 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700578 fMCRec->reset(bounds);
579
580 // We're peering through a lot of structs here. Only at this scope do we
581 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
582 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700583 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700584 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700585}
586
reedd9544982014-09-09 18:46:22 -0700587SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800588 if (device && device->forceConservativeRasterClip()) {
589 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
590 }
reed42b73eb2015-11-20 13:42:42 -0800591
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000592 fAllowSimplifyClip = false;
reed2ff1fce2014-12-11 07:07:37 -0800593 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700594 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700595#ifdef SK_EXPERIMENTAL_SHADOWING
596 fLights = nullptr;
597#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000598
599 fMCRec = (MCRec*)fMCStack.push_back();
Mike Reeda1361362017-03-07 09:37:29 -0500600 new (fMCRec) MCRec;
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500601 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700602 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603
reeda499f902015-05-01 09:34:31 -0700604 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
605 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
Mike Reeda1361362017-03-07 09:37:29 -0500606 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700607
reed@android.com8a1c16f2008-12-17 15:59:43 +0000608 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000609
halcanary96fcdcc2015-08-27 07:41:13 -0700610 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000611
reedf92c8662014-08-18 08:02:43 -0700612 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700613 // The root device and the canvas should always have the same pixel geometry
614 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700615 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800616 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700617 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500618
Mike Reedc42a1cd2017-02-14 14:25:14 -0500619 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
reedf92c8662014-08-18 08:02:43 -0700620 }
msarettfbfa2582016-08-12 08:29:08 -0700621
reedf92c8662014-08-18 08:02:43 -0700622 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000623}
624
reed@google.comcde92112011-07-06 20:00:52 +0000625SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000626 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700627 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000628{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000629 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000630
halcanary96fcdcc2015-08-27 07:41:13 -0700631 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000632}
633
reedd9544982014-09-09 18:46:22 -0700634static SkBitmap make_nopixels(int width, int height) {
635 SkBitmap bitmap;
636 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
637 return bitmap;
638}
639
640class SkNoPixelsBitmapDevice : public SkBitmapDevice {
641public:
robertphillipsfcf78292015-06-19 11:49:52 -0700642 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
643 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800644 {
Mike Reedc42a1cd2017-02-14 14:25:14 -0500645 this->setOrigin(SkMatrix::I(), bounds.x(), bounds.y());
reed78e27682014-11-19 08:04:34 -0800646 }
reedd9544982014-09-09 18:46:22 -0700647
648private:
piotaixrb5fae932014-09-24 13:03:30 -0700649
reedd9544982014-09-09 18:46:22 -0700650 typedef SkBitmapDevice INHERITED;
651};
652
reed96a857e2015-01-25 10:33:58 -0800653SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000654 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800655 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000656{
657 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700658
halcanary385fe4d2015-08-26 13:07:48 -0700659 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
660 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700661}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000662
reed78e27682014-11-19 08:04:34 -0800663SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700664 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700665 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700666{
667 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700668
halcanary385fe4d2015-08-26 13:07:48 -0700669 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700670}
671
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000672SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000673 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700674 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000675{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000676 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700677
reedd9544982014-09-09 18:46:22 -0700678 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679}
680
robertphillipsfcf78292015-06-19 11:49:52 -0700681SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
682 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700683 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700684{
685 inc_canvas();
686
687 this->init(device, flags);
688}
689
reed4a8126e2014-09-22 07:29:03 -0700690SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700691 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700692 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700693{
694 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700695
Hal Canary704cd322016-11-07 14:13:52 -0500696 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
697 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700698}
reed29c857d2014-09-21 10:25:07 -0700699
Mike Reed356f7c22017-01-10 11:58:39 -0500700SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
701 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700702 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
703 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500704 , fAllocator(std::move(alloc))
reed4a8126e2014-09-22 07:29:03 -0700705{
706 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700707
Mike Reed356f7c22017-01-10 11:58:39 -0500708 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500709 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000710}
711
Mike Reed356f7c22017-01-10 11:58:39 -0500712SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
713
reed@android.com8a1c16f2008-12-17 15:59:43 +0000714SkCanvas::~SkCanvas() {
715 // free up the contents of our deque
716 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000717
reed@android.com8a1c16f2008-12-17 15:59:43 +0000718 this->internalRestore(); // restore the last, since we're going away
719
halcanary385fe4d2015-08-26 13:07:48 -0700720 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000721
reed@android.com8a1c16f2008-12-17 15:59:43 +0000722 dec_canvas();
723}
724
fmalita53d9f1c2016-01-25 06:23:54 -0800725#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000726SkDrawFilter* SkCanvas::getDrawFilter() const {
727 return fMCRec->fFilter;
728}
729
730SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700731 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
733 return filter;
734}
fmalita77650002016-01-21 18:47:11 -0800735#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000736
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000737SkMetaData& SkCanvas::getMetaData() {
738 // metadata users are rare, so we lazily allocate it. If that changes we
739 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700740 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000741 fMetaData = new SkMetaData;
742 }
743 return *fMetaData;
744}
745
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746///////////////////////////////////////////////////////////////////////////////
747
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000748void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700749 this->onFlush();
750}
751
752void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000753 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000754 if (device) {
755 device->flush();
756 }
757}
758
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000759SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000760 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000761 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
762}
763
senorblancoafc7cce2016-02-02 18:44:15 -0800764SkIRect SkCanvas::getTopLayerBounds() const {
765 SkBaseDevice* d = this->getTopDevice();
766 if (!d) {
767 return SkIRect::MakeEmpty();
768 }
769 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
770}
771
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000772SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000774 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000775 SkASSERT(rec && rec->fLayer);
776 return rec->fLayer->fDevice;
777}
778
Florin Malita0ed3b642017-01-13 16:56:38 +0000779SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000780 return fMCRec->fTopLayer->fDevice;
781}
782
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000783bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000784 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700785 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700786 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000787 return false;
788 }
789 weAllocated = true;
790 }
791
reedcf01e312015-05-23 19:14:51 -0700792 SkAutoPixmapUnlock unlocker;
793 if (bitmap->requestLock(&unlocker)) {
794 const SkPixmap& pm = unlocker.pixmap();
795 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
796 return true;
797 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000798 }
799
800 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500801 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000802 }
803 return false;
804}
reed@google.com51df9e32010-12-23 19:29:18 +0000805
bsalomon@google.comc6980972011-11-02 19:57:21 +0000806bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000807 SkIRect r = srcRect;
808 const SkISize size = this->getBaseLayerSize();
809 if (!r.intersect(0, 0, size.width(), size.height())) {
810 bitmap->reset();
811 return false;
812 }
813
reed84825042014-09-02 12:50:45 -0700814 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000815 // bitmap will already be reset.
816 return false;
817 }
818 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
819 bitmap->reset();
820 return false;
821 }
822 return true;
823}
824
reed96472de2014-12-10 09:53:42 -0800825bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000826 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000827 if (!device) {
828 return false;
829 }
mtkleinf0f14112014-12-12 08:46:25 -0800830
Matt Sarett03dd6d52017-01-23 12:15:09 -0500831 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000832}
833
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000834bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700835 SkAutoPixmapUnlock unlocker;
836 if (bitmap.requestLock(&unlocker)) {
837 const SkPixmap& pm = unlocker.pixmap();
838 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000839 }
840 return false;
841}
842
Matt Sarett03dd6d52017-01-23 12:15:09 -0500843bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000844 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000845 SkBaseDevice* device = this->getDevice();
846 if (!device) {
847 return false;
848 }
849
Matt Sarett03dd6d52017-01-23 12:15:09 -0500850 // This check gives us an early out and prevents generation ID churn on the surface.
851 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
852 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
853 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
854 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000855 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000856
Matt Sarett03dd6d52017-01-23 12:15:09 -0500857 // Tell our owning surface to bump its generation ID.
858 const bool completeOverwrite =
859 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700860 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700861
Matt Sarett03dd6d52017-01-23 12:15:09 -0500862 // This can still fail, most notably in the case of a invalid color type or alpha type
863 // conversion. We could pull those checks into this function and avoid the unnecessary
864 // generation ID bump. But then we would be performing those checks twice, since they
865 // are also necessary at the bitmap/pixmap entry points.
866 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000867}
reed@google.com51df9e32010-12-23 19:29:18 +0000868
reed@android.com8a1c16f2008-12-17 15:59:43 +0000869//////////////////////////////////////////////////////////////////////////////
870
reed2ff1fce2014-12-11 07:07:37 -0800871void SkCanvas::checkForDeferredSave() {
872 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800873 this->doSave();
874 }
875}
876
reedf0090cb2014-11-26 08:55:51 -0800877int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800878#ifdef SK_DEBUG
879 int count = 0;
880 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
881 for (;;) {
882 const MCRec* rec = (const MCRec*)iter.next();
883 if (!rec) {
884 break;
885 }
886 count += 1 + rec->fDeferredSaveCount;
887 }
888 SkASSERT(count == fSaveCount);
889#endif
890 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800891}
892
893int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800894 fSaveCount += 1;
895 fMCRec->fDeferredSaveCount += 1;
896 return this->getSaveCount() - 1; // return our prev value
897}
898
899void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800900 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700901
902 SkASSERT(fMCRec->fDeferredSaveCount > 0);
903 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800904 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800905}
906
907void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800908 if (fMCRec->fDeferredSaveCount > 0) {
909 SkASSERT(fSaveCount > 1);
910 fSaveCount -= 1;
911 fMCRec->fDeferredSaveCount -= 1;
912 } else {
913 // check for underflow
914 if (fMCStack.count() > 1) {
915 this->willRestore();
916 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700917 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800918 this->internalRestore();
919 this->didRestore();
920 }
reedf0090cb2014-11-26 08:55:51 -0800921 }
922}
923
924void SkCanvas::restoreToCount(int count) {
925 // sanity check
926 if (count < 1) {
927 count = 1;
928 }
mtkleinf0f14112014-12-12 08:46:25 -0800929
reedf0090cb2014-11-26 08:55:51 -0800930 int n = this->getSaveCount() - count;
931 for (int i = 0; i < n; ++i) {
932 this->restore();
933 }
934}
935
reed2ff1fce2014-12-11 07:07:37 -0800936void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000937 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700938 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000939 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000940
Mike Reedc42a1cd2017-02-14 14:25:14 -0500941 FOR_EACH_TOP_DEVICE(device->save());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000942}
943
reed4960eee2015-12-18 07:09:18 -0800944bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -0800945 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000946}
947
reed4960eee2015-12-18 07:09:18 -0800948bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -0700949 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -0500950 SkIRect clipBounds = this->getDeviceClipBounds();
951 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000952 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000953 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000954
reed96e657d2015-03-10 17:30:07 -0700955 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
956
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000957 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -0700958 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -0800959 if (bounds && !imageFilter->canComputeFastBounds()) {
960 bounds = nullptr;
961 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000962 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000963 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700964 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000966
reed96e657d2015-03-10 17:30:07 -0700967 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968 r.roundOut(&ir);
969 // early exit if the layer's bounds are clipped out
970 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -0800971 if (BoundsAffectsClip(saveLayerFlags)) {
Mike Reeda1361362017-03-07 09:37:29 -0500972 fMCRec->fTopLayer->fDevice->clipRegion(SkRegion(), SkClipOp::kIntersect); // empty
reed1f836ee2014-07-07 07:49:34 -0700973 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -0700974 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000975 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000976 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977 }
978 } else { // no user bounds, so just use the clip
979 ir = clipBounds;
980 }
reed180aec42015-03-11 10:39:04 -0700981 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982
reed4960eee2015-12-18 07:09:18 -0800983 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -0700984 // Simplify the current clips since they will be applied properly during restore()
reed180aec42015-03-11 10:39:04 -0700985 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -0700986 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000987 }
988
989 if (intersection) {
990 *intersection = ir;
991 }
992 return true;
993}
994
reed4960eee2015-12-18 07:09:18 -0800995
reed4960eee2015-12-18 07:09:18 -0800996int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
997 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000998}
999
reed70ee31b2015-12-10 13:44:45 -08001000int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001001 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1002}
1003
1004int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1005 SaveLayerRec rec(origRec);
1006 if (gIgnoreSaveLayerBounds) {
1007 rec.fBounds = nullptr;
1008 }
1009 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1010 fSaveCount += 1;
1011 this->internalSaveLayer(rec, strategy);
1012 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001013}
1014
reeda2217ef2016-07-20 06:04:34 -07001015void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001016 SkBaseDevice* dst, const SkIPoint& dstOrigin,
Mike Reeda1361362017-03-07 09:37:29 -05001017 const SkMatrix& ctm) {
reeda2217ef2016-07-20 06:04:34 -07001018 SkDraw draw;
1019 SkRasterClip rc;
1020 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1021 if (!dst->accessPixels(&draw.fDst)) {
1022 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001023 }
reeda2217ef2016-07-20 06:04:34 -07001024 draw.fMatrix = &SkMatrix::I();
1025 draw.fRC = &rc;
robertphillips7354a4b2015-12-16 05:08:27 -08001026
1027 SkPaint p;
Mike Reedc61abee2017-02-28 17:45:27 -05001028 if (filter) {
1029 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1030 }
reeda2217ef2016-07-20 06:04:34 -07001031
Mike Reedc42a1cd2017-02-14 14:25:14 -05001032 int x = src->getOrigin().x() - dstOrigin.x();
1033 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001034 auto special = src->snapSpecial();
1035 if (special) {
Mike Reeda1361362017-03-07 09:37:29 -05001036 dst->drawSpecial(special.get(), x, y, p);
reeda2217ef2016-07-20 06:04:34 -07001037 }
robertphillips7354a4b2015-12-16 05:08:27 -08001038}
reed70ee31b2015-12-10 13:44:45 -08001039
reed129ed1c2016-02-22 06:42:31 -08001040static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1041 const SkPaint* paint) {
1042 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1043 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001044 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001045 const bool hasImageFilter = paint && paint->getImageFilter();
1046
1047 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1048 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1049 // force to L32
1050 return SkImageInfo::MakeN32(w, h, alphaType);
1051 } else {
1052 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001053 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001054 }
1055}
1056
reed4960eee2015-12-18 07:09:18 -08001057void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1058 const SkRect* bounds = rec.fBounds;
1059 const SkPaint* paint = rec.fPaint;
1060 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1061
reed8c30a812016-04-20 16:36:51 -07001062 SkLazyPaint lazyP;
1063 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1064 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001065 SkMatrix remainder;
1066 SkSize scale;
1067 /*
1068 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1069 * but they do handle scaling. To accommodate this, we do the following:
1070 *
1071 * 1. Stash off the current CTM
1072 * 2. Decompose the CTM into SCALE and REMAINDER
1073 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1074 * contains the REMAINDER
1075 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1076 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1077 * of the original imagefilter, and draw that (via drawSprite)
1078 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1079 *
1080 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1081 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1082 */
reed96a04f32016-04-25 09:25:15 -07001083 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001084 stashedMatrix.decomposeScale(&scale, &remainder))
1085 {
1086 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1087 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1088 SkPaint* p = lazyP.set(*paint);
1089 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1090 SkFilterQuality::kLow_SkFilterQuality,
1091 sk_ref_sp(imageFilter)));
1092 imageFilter = p->getImageFilter();
1093 paint = p;
1094 }
reed8c30a812016-04-20 16:36:51 -07001095
junov@chromium.orga907ac32012-02-24 21:54:07 +00001096 // do this before we create the layer. We don't call the public save() since
1097 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001098 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001099
junov@chromium.orga907ac32012-02-24 21:54:07 +00001100 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001101 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001102 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001103 }
1104
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001105 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1106 // the clipRectBounds() call above?
1107 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001108 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001109 }
1110
reed4960eee2015-12-18 07:09:18 -08001111 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001112 SkPixelGeometry geo = fProps.pixelGeometry();
1113 if (paint) {
reed76033be2015-03-14 10:54:31 -07001114 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001115 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001116 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001117 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001118 }
1119 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001120
robertphillips5139e502016-07-19 05:10:40 -07001121 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001122 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001123 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001124 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001125 }
reedb2db8982014-11-13 12:41:02 -08001126
robertphillips5139e502016-07-19 05:10:40 -07001127 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001128 paint);
1129
Hal Canary704cd322016-11-07 14:13:52 -05001130 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001131 {
reed70ee31b2015-12-10 13:44:45 -08001132 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001133 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001134 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001135 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001136 preserveLCDText,
1137 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001138 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1139 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001140 return;
reed61f501f2015-04-29 08:34:00 -07001141 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001142 }
Hal Canary704cd322016-11-07 14:13:52 -05001143 DeviceCM* layer =
Mike Reeda1361362017-03-07 09:37:29 -05001144 new DeviceCM(newDevice.get(), paint, this, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145
Mike Reedb43a3e02017-02-11 10:18:58 -05001146 // only have a "next" if this new layer doesn't affect the clip (rare)
1147 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001148 fMCRec->fLayer = layer;
1149 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001150
Mike Reedc61abee2017-02-28 17:45:27 -05001151 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001152 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
Mike Reeda1361362017-03-07 09:37:29 -05001153 fMCRec->fMatrix);
reeda2217ef2016-07-20 06:04:34 -07001154 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001155
Mike Reedc42a1cd2017-02-14 14:25:14 -05001156 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1157
1158 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1159 if (layer->fNext) {
1160 // need to punch a hole in the previous device, so we don't draw there, given that
1161 // the new top-layer will allow drawing to happen "below" it.
1162 SkRegion hole(ir);
1163 do {
1164 layer = layer->fNext;
1165 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1166 } while (layer->fNext);
1167 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001168}
1169
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001170int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001171 if (0xFF == alpha) {
1172 return this->saveLayer(bounds, nullptr);
1173 } else {
1174 SkPaint tmpPaint;
1175 tmpPaint.setAlpha(alpha);
1176 return this->saveLayer(bounds, &tmpPaint);
1177 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001178}
1179
reed@android.com8a1c16f2008-12-17 15:59:43 +00001180void SkCanvas::internalRestore() {
1181 SkASSERT(fMCStack.count() != 0);
1182
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001183 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001184 DeviceCM* layer = fMCRec->fLayer; // may be null
1185 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001186 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001187
1188 // now do the normal restore()
1189 fMCRec->~MCRec(); // balanced in save()
1190 fMCStack.pop_back();
1191 fMCRec = (MCRec*)fMCStack.back();
1192
Mike Reedc42a1cd2017-02-14 14:25:14 -05001193 if (fMCRec) {
1194 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1195 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001196
reed@android.com8a1c16f2008-12-17 15:59:43 +00001197 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1198 since if we're being recorded, we don't want to record this (the
1199 recorder will have already recorded the restore).
1200 */
bsalomon49f085d2014-09-05 13:34:00 -07001201 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001202 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001203 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001204 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001205 // restore what we smashed in internalSaveLayer
1206 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001207 // reset this, since internalDrawDevice will have set it to true
halcanary385fe4d2015-08-26 13:07:48 -07001208 delete layer;
reedb679ca82015-04-07 04:40:48 -07001209 } else {
1210 // we're at the root
reeda499f902015-05-01 09:34:31 -07001211 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001212 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001213 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001214 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001215 }
msarettfbfa2582016-08-12 08:29:08 -07001216
1217 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001218 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001219 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1220 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221}
1222
reede8f30622016-03-23 18:59:25 -07001223sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001224 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001225 props = &fProps;
1226 }
1227 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001228}
1229
reede8f30622016-03-23 18:59:25 -07001230sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001231 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001232 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001233}
1234
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001235SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001236 return this->onImageInfo();
1237}
1238
1239SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001240 SkBaseDevice* dev = this->getDevice();
1241 if (dev) {
1242 return dev->imageInfo();
1243 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001244 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001245 }
1246}
1247
brianosman898235c2016-04-06 07:38:23 -07001248bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001249 return this->onGetProps(props);
1250}
1251
1252bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001253 SkBaseDevice* dev = this->getDevice();
1254 if (dev) {
1255 if (props) {
1256 *props = fProps;
1257 }
1258 return true;
1259 } else {
1260 return false;
1261 }
1262}
1263
reed6ceeebd2016-03-09 14:26:26 -08001264bool SkCanvas::peekPixels(SkPixmap* pmap) {
1265 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001266}
1267
reed884e97c2015-05-26 11:31:54 -07001268bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001269 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001270 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001271}
1272
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001273void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001274 SkPixmap pmap;
1275 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001276 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001277 }
1278 if (info) {
1279 *info = pmap.info();
1280 }
1281 if (rowBytes) {
1282 *rowBytes = pmap.rowBytes();
1283 }
1284 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001285 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001286 }
reed884e97c2015-05-26 11:31:54 -07001287 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001288}
1289
reed884e97c2015-05-26 11:31:54 -07001290bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001291 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001292 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001293}
1294
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296
reed7503d602016-07-15 14:23:29 -07001297void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001299 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300 paint = &tmp;
1301 }
reed@google.com4b226022011-01-11 18:32:13 +00001302
reed@google.com8926b162012-03-23 15:36:36 +00001303 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001304
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001306 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001307 paint = &looper.paint();
1308 SkImageFilter* filter = paint->getImageFilter();
1309 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001310 if (filter) {
1311 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1312 if (specialImage) {
Mike Reeda1361362017-03-07 09:37:29 -05001313 dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint);
Robert Phillips833dcf42016-11-18 08:44:13 -05001314 }
reed@google.com76dd2772012-01-05 21:15:07 +00001315 } else {
Mike Reeda1361362017-03-07 09:37:29 -05001316 dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001317 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318 }
reeda2217ef2016-07-20 06:04:34 -07001319
reed@google.com4e2b3d32011-04-07 14:18:59 +00001320 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321}
1322
reed32704672015-12-16 08:27:10 -08001323/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001324
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001325void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001326 if (dx || dy) {
1327 this->checkForDeferredSave();
reedfe69b502016-09-12 06:31:48 -07001328 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001329
reedfe69b502016-09-12 06:31:48 -07001330 // Translate shouldn't affect the is-scale-translateness of the matrix.
1331 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001332
Mike Reedc42a1cd2017-02-14 14:25:14 -05001333 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001334
reedfe69b502016-09-12 06:31:48 -07001335 this->didTranslate(dx,dy);
1336 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337}
1338
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001339void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001340 SkMatrix m;
1341 m.setScale(sx, sy);
1342 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343}
1344
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001345void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001346 SkMatrix m;
1347 m.setRotate(degrees);
1348 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001349}
1350
bungeman7438bfc2016-07-12 15:01:19 -07001351void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1352 SkMatrix m;
1353 m.setRotate(degrees, px, py);
1354 this->concat(m);
1355}
1356
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001357void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001358 SkMatrix m;
1359 m.setSkew(sx, sy);
1360 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001361}
1362
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001363void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001364 if (matrix.isIdentity()) {
1365 return;
1366 }
1367
reed2ff1fce2014-12-11 07:07:37 -08001368 this->checkForDeferredSave();
reed1f836ee2014-07-07 07:49:34 -07001369 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001370 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001371
Mike Reed7627fa52017-02-08 10:07:53 -05001372 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
Mike Reed7627fa52017-02-08 10:07:53 -05001373
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001374 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001375}
1376
reed8c30a812016-04-20 16:36:51 -07001377void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed1f836ee2014-07-07 07:49:34 -07001378 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001379 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001380
Mike Reedc42a1cd2017-02-14 14:25:14 -05001381 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
reed8c30a812016-04-20 16:36:51 -07001382}
1383
1384void SkCanvas::setMatrix(const SkMatrix& matrix) {
1385 this->checkForDeferredSave();
1386 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001387 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001388}
1389
reed@android.com8a1c16f2008-12-17 15:59:43 +00001390void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001391 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001392}
1393
vjiaoblack95302da2016-07-21 10:25:54 -07001394#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001395void SkCanvas::translateZ(SkScalar z) {
1396 this->checkForDeferredSave();
1397 this->fMCRec->fCurDrawDepth += z;
1398 this->didTranslateZ(z);
1399}
1400
1401SkScalar SkCanvas::getZ() const {
1402 return this->fMCRec->fCurDrawDepth;
1403}
1404
vjiaoblack95302da2016-07-21 10:25:54 -07001405void SkCanvas::setLights(sk_sp<SkLights> lights) {
1406 this->fLights = lights;
1407}
1408
1409sk_sp<SkLights> SkCanvas::getLights() const {
1410 return this->fLights;
1411}
1412#endif
1413
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414//////////////////////////////////////////////////////////////////////////////
1415
Mike Reedc1f77742016-12-09 09:00:50 -05001416void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001417 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001418 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1419 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001420}
1421
Mike Reedc1f77742016-12-09 09:00:50 -05001422void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001423 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001424
Mike Reed7627fa52017-02-08 10:07:53 -05001425 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
Mike Reed7627fa52017-02-08 10:07:53 -05001426
reedc64eff52015-11-21 12:39:45 -08001427 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001428 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1429 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001430 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001431}
1432
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001433void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1434 fClipRestrictionRect = rect;
Mike Reedd519d482017-02-16 11:04:52 -05001435 if (fClipRestrictionRect.isEmpty()) {
1436 // we notify the device, but we *dont* resolve deferred saves (since we're just
1437 // removing the restriction if the rect is empty. how I hate this api.
Mike Reedd519d482017-02-16 11:04:52 -05001438 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedd519d482017-02-16 11:04:52 -05001439 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001440 this->checkForDeferredSave();
Mike Reedd519d482017-02-16 11:04:52 -05001441 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001442 AutoValidateClip avc(this);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001443 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001444 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1445 }
1446}
1447
Mike Reedc1f77742016-12-09 09:00:50 -05001448void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001449 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001450 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001451 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001452 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1453 } else {
1454 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001455 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001456}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001457
Mike Reedc1f77742016-12-09 09:00:50 -05001458void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001459 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001460
Brian Salomona3b45d42016-10-03 11:36:16 -04001461 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001462
Mike Reed7627fa52017-02-08 10:07:53 -05001463 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
Mike Reeda1361362017-03-07 09:37:29 -05001464
Brian Salomona3b45d42016-10-03 11:36:16 -04001465 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1466 isAA);
1467 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@google.com4ed0fb72012-12-12 20:48:18 +00001468}
1469
Mike Reedc1f77742016-12-09 09:00:50 -05001470void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001471 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001472 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001473
1474 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1475 SkRect r;
1476 if (path.isRect(&r)) {
1477 this->onClipRect(r, op, edgeStyle);
1478 return;
1479 }
1480 SkRRect rrect;
1481 if (path.isOval(&r)) {
1482 rrect.setOval(r);
1483 this->onClipRRect(rrect, op, edgeStyle);
1484 return;
1485 }
1486 if (path.isRRect(&rrect)) {
1487 this->onClipRRect(rrect, op, edgeStyle);
1488 return;
1489 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001490 }
robertphillips39f05382015-11-24 09:30:12 -08001491
1492 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001493}
1494
Mike Reedc1f77742016-12-09 09:00:50 -05001495void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001496 AutoValidateClip avc(this);
1497
Brian Salomona3b45d42016-10-03 11:36:16 -04001498 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001499
Mike Reed7627fa52017-02-08 10:07:53 -05001500 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501
Brian Salomona3b45d42016-10-03 11:36:16 -04001502 const SkPath* rasterClipPath = &path;
1503 const SkMatrix* matrix = &fMCRec->fMatrix;
Brian Salomona3b45d42016-10-03 11:36:16 -04001504 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1505 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001506 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001507}
1508
Mike Reedc1f77742016-12-09 09:00:50 -05001509void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001510 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001511 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001512}
1513
Mike Reedc1f77742016-12-09 09:00:50 -05001514void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001515 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
Mike Reeda1361362017-03-07 09:37:29 -05001516
reed@google.com5c3d1472011-02-22 19:12:23 +00001517 AutoValidateClip avc(this);
1518
reed73603f32016-09-20 08:42:38 -07001519 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001520 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001521}
1522
reed@google.com819c9212011-02-23 18:56:55 +00001523#ifdef SK_DEBUG
1524void SkCanvas::validateClip() const {
1525 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001526 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001527 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001528 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001529 return;
1530 }
reed@google.com819c9212011-02-23 18:56:55 +00001531}
1532#endif
1533
reed@google.com90c07ea2012-04-13 13:50:27 +00001534void SkCanvas::replayClips(ClipVisitor* visitor) const {
Mike Reeda1361362017-03-07 09:37:29 -05001535#if 0
reed687fa1c2015-04-07 08:00:56 -07001536 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001537 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001538
halcanary96fcdcc2015-08-27 07:41:13 -07001539 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001540 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001541 }
Mike Reeda1361362017-03-07 09:37:29 -05001542#endif
1543}
1544
1545bool SkCanvas::androidFramework_isClipAA() const {
1546 bool containsAA = false;
1547
1548 FOR_EACH_TOP_DEVICE(containsAA |= device->onClipIsAA());
1549
1550 return containsAA;
1551}
1552
1553class RgnAccumulator {
1554 SkRegion* fRgn;
1555public:
1556 RgnAccumulator(SkRegion* total) : fRgn(total) {}
1557 void accumulate(SkBaseDevice* device, SkRegion* rgn) {
1558 SkIPoint origin = device->getOrigin();
1559 if (origin.x() | origin.y()) {
1560 rgn->translate(origin.x(), origin.y());
1561 }
1562 fRgn->op(*rgn, SkRegion::kUnion_Op);
1563 }
1564};
1565
1566void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1567 RgnAccumulator accum(rgn);
1568 SkRegion tmp;
1569
1570 rgn->setEmpty();
1571 FOR_EACH_TOP_DEVICE(device->onAsRgnClip(&tmp); accum.accumulate(device, &tmp));
reed@google.com90c07ea2012-04-13 13:50:27 +00001572}
1573
reed@google.com5c3d1472011-02-22 19:12:23 +00001574///////////////////////////////////////////////////////////////////////////////
1575
reed@google.com754de5f2014-02-24 19:38:20 +00001576bool SkCanvas::isClipEmpty() const {
Mike Reeda1361362017-03-07 09:37:29 -05001577 SkBaseDevice* dev = this->getTopDevice();
1578 // if no device we return true
1579 return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
reed@google.com754de5f2014-02-24 19:38:20 +00001580}
1581
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001582bool SkCanvas::isClipRect() const {
Mike Reeda1361362017-03-07 09:37:29 -05001583 SkBaseDevice* dev = this->getTopDevice();
1584 // if no device we return false
1585 return dev && dev->onGetClipType() == SkBaseDevice::kRect_ClipType;
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001586}
1587
msarettfbfa2582016-08-12 08:29:08 -07001588static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1589#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1590 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1591 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1592 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1593 return 0xF != _mm_movemask_ps(mask);
1594#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1595 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1596 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1597 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1598 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1599#else
1600 SkRect devRectAsRect;
1601 SkRect devClipAsRect;
1602 devRect.store(&devRectAsRect.fLeft);
1603 devClip.store(&devClipAsRect.fLeft);
1604 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1605#endif
1606}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001607
msarettfbfa2582016-08-12 08:29:08 -07001608// It's important for this function to not be inlined. Otherwise the compiler will share code
1609// between the fast path and the slow path, resulting in two slow paths.
1610static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1611 const SkMatrix& matrix) {
1612 SkRect deviceRect;
1613 matrix.mapRect(&deviceRect, src);
1614 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1615}
1616
1617bool SkCanvas::quickReject(const SkRect& src) const {
1618#ifdef SK_DEBUG
1619 // Verify that fDeviceClipBounds are set properly.
1620 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001621 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001622 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001623 } else {
msarettfbfa2582016-08-12 08:29:08 -07001624 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001625 }
msarettfbfa2582016-08-12 08:29:08 -07001626
msarett9637ea92016-08-18 14:03:30 -07001627 // Verify that fIsScaleTranslate is set properly.
1628 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001629#endif
1630
msarett9637ea92016-08-18 14:03:30 -07001631 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001632 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1633 }
1634
1635 // We inline the implementation of mapScaleTranslate() for the fast path.
1636 float sx = fMCRec->fMatrix.getScaleX();
1637 float sy = fMCRec->fMatrix.getScaleY();
1638 float tx = fMCRec->fMatrix.getTranslateX();
1639 float ty = fMCRec->fMatrix.getTranslateY();
1640 Sk4f scale(sx, sy, sx, sy);
1641 Sk4f trans(tx, ty, tx, ty);
1642
1643 // Apply matrix.
1644 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1645
1646 // Make sure left < right, top < bottom.
1647 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1648 Sk4f min = Sk4f::Min(ltrb, rblt);
1649 Sk4f max = Sk4f::Max(ltrb, rblt);
1650 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1651 // ARM this sequence generates the fastest (a single instruction).
1652 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1653
1654 // Check if the device rect is NaN or outside the clip.
1655 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001656}
1657
reed@google.com3b3e8952012-08-16 20:53:31 +00001658bool SkCanvas::quickReject(const SkPath& path) const {
1659 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001660}
1661
Mike Reed42e8c532017-01-23 14:09:13 -05001662SkRect SkCanvas::onGetLocalClipBounds() const {
1663 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001664 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001665 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001666 }
1667
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001668 SkMatrix inverse;
1669 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001670 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001671 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001672 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001673
Mike Reed42e8c532017-01-23 14:09:13 -05001674 SkRect bounds;
1675 SkRect r;
1676 // adjust it outwards in case we are antialiasing
1677 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001678
Mike Reed42e8c532017-01-23 14:09:13 -05001679 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1680 ibounds.fRight + inset, ibounds.fBottom + inset);
1681 inverse.mapRect(&bounds, r);
1682 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001683}
1684
Mike Reed42e8c532017-01-23 14:09:13 -05001685SkIRect SkCanvas::onGetDeviceClipBounds() const {
Mike Reeda1361362017-03-07 09:37:29 -05001686 return fMCRec->fRasterClip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001687}
1688
reed@android.com8a1c16f2008-12-17 15:59:43 +00001689const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001690 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001691}
1692
Brian Osman11052242016-10-27 14:47:55 -04001693GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001694 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001695 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001696}
1697
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001698GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001699 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001700 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001701}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001702
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001703void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1704 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001705 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001706 if (outer.isEmpty()) {
1707 return;
1708 }
1709 if (inner.isEmpty()) {
1710 this->drawRRect(outer, paint);
1711 return;
1712 }
1713
1714 // We don't have this method (yet), but technically this is what we should
1715 // be able to assert...
1716 // SkASSERT(outer.contains(inner));
1717 //
1718 // For now at least check for containment of bounds
1719 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1720
1721 this->onDrawDRRect(outer, inner, paint);
1722}
1723
reed41af9662015-01-05 07:49:08 -08001724// These need to stop being virtual -- clients need to override the onDraw... versions
1725
1726void SkCanvas::drawPaint(const SkPaint& paint) {
1727 this->onDrawPaint(paint);
1728}
1729
1730void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1731 this->onDrawRect(r, paint);
1732}
1733
msarettdca352e2016-08-26 06:37:45 -07001734void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1735 if (region.isEmpty()) {
1736 return;
1737 }
1738
1739 if (region.isRect()) {
1740 return this->drawIRect(region.getBounds(), paint);
1741 }
1742
1743 this->onDrawRegion(region, paint);
1744}
1745
reed41af9662015-01-05 07:49:08 -08001746void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1747 this->onDrawOval(r, paint);
1748}
1749
1750void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1751 this->onDrawRRect(rrect, paint);
1752}
1753
1754void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1755 this->onDrawPoints(mode, count, pts, paint);
1756}
1757
1758void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001759 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001760 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001761 this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices,
1762 indexCount, paint);
1763}
1764
1765void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint,
1766 uint32_t flags) {
1767 RETURN_ON_NULL(vertices);
1768 this->onDrawVerticesObject(std::move(vertices), mode, paint, flags);
reed41af9662015-01-05 07:49:08 -08001769}
1770
1771void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1772 this->onDrawPath(path, paint);
1773}
1774
reeda85d4d02015-05-06 12:56:48 -07001775void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001776 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001777 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001778}
1779
reede47829b2015-08-06 10:02:53 -07001780void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1781 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001782 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001783 if (dst.isEmpty() || src.isEmpty()) {
1784 return;
1785 }
1786 this->onDrawImageRect(image, &src, dst, paint, constraint);
1787}
reed41af9662015-01-05 07:49:08 -08001788
reed84984ef2015-07-17 07:09:43 -07001789void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1790 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001791 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001792 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001793}
1794
reede47829b2015-08-06 10:02:53 -07001795void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1796 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001797 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001798 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1799 constraint);
1800}
reede47829b2015-08-06 10:02:53 -07001801
reed4c21dc52015-06-25 12:32:03 -07001802void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1803 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001804 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001805 if (dst.isEmpty()) {
1806 return;
1807 }
msarett552bca92016-08-03 06:53:26 -07001808 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1809 this->onDrawImageNine(image, center, dst, paint);
1810 } else {
reede47829b2015-08-06 10:02:53 -07001811 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001812 }
reed4c21dc52015-06-25 12:32:03 -07001813}
1814
msarett16882062016-08-16 09:31:08 -07001815void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1816 const SkPaint* paint) {
1817 RETURN_ON_NULL(image);
1818 if (dst.isEmpty()) {
1819 return;
1820 }
msarett71df2d72016-09-30 12:41:42 -07001821
1822 SkIRect bounds;
1823 Lattice latticePlusBounds = lattice;
1824 if (!latticePlusBounds.fBounds) {
1825 bounds = SkIRect::MakeWH(image->width(), image->height());
1826 latticePlusBounds.fBounds = &bounds;
1827 }
1828
1829 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1830 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001831 } else {
1832 this->drawImageRect(image, dst, paint);
1833 }
1834}
1835
reed41af9662015-01-05 07:49:08 -08001836void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001837 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001838 return;
1839 }
reed41af9662015-01-05 07:49:08 -08001840 this->onDrawBitmap(bitmap, dx, dy, paint);
1841}
1842
reede47829b2015-08-06 10:02:53 -07001843void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001844 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001845 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001846 return;
1847 }
reede47829b2015-08-06 10:02:53 -07001848 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001849}
1850
reed84984ef2015-07-17 07:09:43 -07001851void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1852 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001853 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001854}
1855
reede47829b2015-08-06 10:02:53 -07001856void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1857 SrcRectConstraint constraint) {
1858 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1859 constraint);
1860}
reede47829b2015-08-06 10:02:53 -07001861
reed41af9662015-01-05 07:49:08 -08001862void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1863 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001864 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001865 return;
1866 }
msarett552bca92016-08-03 06:53:26 -07001867 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1868 this->onDrawBitmapNine(bitmap, center, dst, paint);
1869 } else {
reeda5517e22015-07-14 10:54:12 -07001870 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001871 }
reed41af9662015-01-05 07:49:08 -08001872}
1873
msarettc573a402016-08-02 08:05:56 -07001874void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1875 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001876 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001877 return;
1878 }
msarett71df2d72016-09-30 12:41:42 -07001879
1880 SkIRect bounds;
1881 Lattice latticePlusBounds = lattice;
1882 if (!latticePlusBounds.fBounds) {
1883 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1884 latticePlusBounds.fBounds = &bounds;
1885 }
1886
1887 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1888 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001889 } else {
msarett16882062016-08-16 09:31:08 -07001890 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001891 }
msarettc573a402016-08-02 08:05:56 -07001892}
1893
reed71c3c762015-06-24 10:29:17 -07001894void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001895 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001896 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001897 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001898 if (count <= 0) {
1899 return;
1900 }
Joe Gregorioc4859072017-01-20 14:21:27 +00001901 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07001902 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04001903 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07001904}
1905
reedf70b5312016-03-04 16:36:20 -08001906void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
1907 if (key) {
1908 this->onDrawAnnotation(rect, key, value);
1909 }
1910}
1911
reede47829b2015-08-06 10:02:53 -07001912void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1913 const SkPaint* paint, SrcRectConstraint constraint) {
1914 if (src) {
1915 this->drawImageRect(image, *src, dst, paint, constraint);
1916 } else {
1917 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1918 dst, paint, constraint);
1919 }
1920}
1921void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1922 const SkPaint* paint, SrcRectConstraint constraint) {
1923 if (src) {
1924 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1925 } else {
1926 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1927 dst, paint, constraint);
1928 }
1929}
1930
tomhudsoncb3bd182016-05-18 07:24:16 -07001931void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
1932 SkIRect layer_bounds = this->getTopLayerBounds();
1933 if (matrix) {
1934 *matrix = this->getTotalMatrix();
1935 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
1936 }
1937 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05001938 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07001939 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
1940 }
1941}
1942
reed@android.com8a1c16f2008-12-17 15:59:43 +00001943//////////////////////////////////////////////////////////////////////////////
1944// These are the virtual drawing methods
1945//////////////////////////////////////////////////////////////////////////////
1946
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001947void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001948 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001949 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1950 }
1951}
1952
reed41af9662015-01-05 07:49:08 -08001953void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001954 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001955 this->internalDrawPaint(paint);
1956}
1957
1958void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001959 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001960
1961 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001962 iter.fDevice->drawPaint(looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001963 }
1964
reed@google.com4e2b3d32011-04-07 14:18:59 +00001965 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001966}
1967
reed41af9662015-01-05 07:49:08 -08001968void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1969 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001970 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001971 if ((long)count <= 0) {
1972 return;
1973 }
1974
Mike Reed822128b2017-02-28 16:41:03 -05001975 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07001976 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00001977 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001978 // special-case 2 points (common for drawing a single line)
1979 if (2 == count) {
1980 r.set(pts[0], pts[1]);
1981 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001982 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001983 }
Mike Reed822128b2017-02-28 16:41:03 -05001984 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07001985 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
1986 return;
1987 }
1988 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001989 }
reed@google.coma584aed2012-05-16 14:06:02 +00001990
halcanary96fcdcc2015-08-27 07:41:13 -07001991 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001992
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001993 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001994
reed@android.com8a1c16f2008-12-17 15:59:43 +00001995 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05001996 iter.fDevice->drawPoints(mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001997 }
reed@google.com4b226022011-01-11 18:32:13 +00001998
reed@google.com4e2b3d32011-04-07 14:18:59 +00001999 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002000}
2001
reed4a167172016-08-18 17:15:25 -07002002static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2003 return ((intptr_t)paint.getImageFilter() |
2004#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2005 (intptr_t)canvas->getDrawFilter() |
2006#endif
2007 (intptr_t)paint.getLooper() ) != 0;
2008}
2009
reed41af9662015-01-05 07:49:08 -08002010void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002011 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002012 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002013 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2014 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2015 SkRect tmp(r);
2016 tmp.sort();
2017
Mike Reed822128b2017-02-28 16:41:03 -05002018 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002019 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2020 return;
2021 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002022 }
reed@google.com4b226022011-01-11 18:32:13 +00002023
reed4a167172016-08-18 17:15:25 -07002024 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002025 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002026
reed4a167172016-08-18 17:15:25 -07002027 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002028 iter.fDevice->drawRect(r, looper.paint());
reed4a167172016-08-18 17:15:25 -07002029 }
2030
2031 LOOPER_END
2032 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002033 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002034 SkDrawIter iter(this);
2035 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002036 iter.fDevice->drawRect(r, paint);
reed4a167172016-08-18 17:15:25 -07002037 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002038 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002039}
2040
msarett44df6512016-08-25 13:54:30 -07002041void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002042 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002043 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002044 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002045 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2046 return;
2047 }
msarett44df6512016-08-25 13:54:30 -07002048 }
2049
Mike Reed822128b2017-02-28 16:41:03 -05002050 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002051
2052 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002053 iter.fDevice->drawRegion(region, looper.paint());
msarett44df6512016-08-25 13:54:30 -07002054 }
2055
2056 LOOPER_END
2057}
2058
reed41af9662015-01-05 07:49:08 -08002059void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002060 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002061 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002062 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002063 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2064 return;
2065 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002066 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002067
Mike Reed822128b2017-02-28 16:41:03 -05002068 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002069
2070 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002071 iter.fDevice->drawOval(oval, looper.paint());
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002072 }
2073
2074 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002075}
2076
bsalomonac3aa242016-08-19 11:25:19 -07002077void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2078 SkScalar sweepAngle, bool useCenter,
2079 const SkPaint& paint) {
2080 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002081 if (paint.canComputeFastBounds()) {
2082 SkRect storage;
2083 // Note we're using the entire oval as the bounds.
2084 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2085 return;
2086 }
bsalomonac3aa242016-08-19 11:25:19 -07002087 }
2088
Mike Reed822128b2017-02-28 16:41:03 -05002089 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002090
2091 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002092 iter.fDevice->drawArc(oval, startAngle, sweepAngle, useCenter, looper.paint());
bsalomonac3aa242016-08-19 11:25:19 -07002093 }
2094
2095 LOOPER_END
2096}
2097
reed41af9662015-01-05 07:49:08 -08002098void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002099 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002100 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002101 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002102 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2103 return;
2104 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002105 }
2106
2107 if (rrect.isRect()) {
2108 // call the non-virtual version
2109 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002110 return;
2111 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002112 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002113 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2114 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002115 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002116
Mike Reed822128b2017-02-28 16:41:03 -05002117 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002118
2119 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002120 iter.fDevice->drawRRect(rrect, looper.paint());
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002121 }
2122
2123 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002124}
2125
Mike Reed822128b2017-02-28 16:41:03 -05002126void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002127 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002128 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002129 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2130 return;
2131 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002132 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002133
Mike Reed822128b2017-02-28 16:41:03 -05002134 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002135
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002136 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002137 iter.fDevice->drawDRRect(outer, inner, looper.paint());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002138 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002139
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002140 LOOPER_END
2141}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002142
reed41af9662015-01-05 07:49:08 -08002143void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002144 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002145 if (!path.isFinite()) {
2146 return;
2147 }
2148
Mike Reed822128b2017-02-28 16:41:03 -05002149 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002150 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002151 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002152 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2153 return;
2154 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002155 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002156
Mike Reed822128b2017-02-28 16:41:03 -05002157 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002158 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002159 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002160 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002161 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002162 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002163
Mike Reed822128b2017-02-28 16:41:03 -05002164 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002165
2166 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002167 iter.fDevice->drawPath(path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002168 }
2169
reed@google.com4e2b3d32011-04-07 14:18:59 +00002170 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002171}
2172
reed262a71b2015-12-05 13:07:27 -08002173bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002174 if (!paint.getImageFilter()) {
2175 return false;
2176 }
2177
2178 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002179 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002180 return false;
2181 }
2182
2183 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2184 // Once we can filter and the filter will return a result larger than itself, we should be
2185 // able to remove this constraint.
2186 // skbug.com/4526
2187 //
2188 SkPoint pt;
2189 ctm.mapXY(x, y, &pt);
2190 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2191 return ir.contains(fMCRec->fRasterClip.getBounds());
2192}
2193
reeda85d4d02015-05-06 12:56:48 -07002194void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002195 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002196 SkRect bounds = SkRect::MakeXYWH(x, y,
2197 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002198 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002199 SkRect tmp = bounds;
2200 if (paint) {
2201 paint->computeFastBounds(tmp, &tmp);
2202 }
2203 if (this->quickReject(tmp)) {
2204 return;
2205 }
reeda85d4d02015-05-06 12:56:48 -07002206 }
halcanary9d524f22016-03-29 09:03:52 -07002207
reeda85d4d02015-05-06 12:56:48 -07002208 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002209 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002210 paint = lazy.init();
2211 }
reed262a71b2015-12-05 13:07:27 -08002212
reeda2217ef2016-07-20 06:04:34 -07002213 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002214 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2215 *paint);
2216 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002217 special = this->getDevice()->makeSpecial(image);
2218 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002219 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002220 }
2221 }
2222
reed262a71b2015-12-05 13:07:27 -08002223 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2224
reeda85d4d02015-05-06 12:56:48 -07002225 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002226 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002227 if (special) {
2228 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002229 iter.fDevice->ctm().mapXY(x, y, &pt);
2230 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002231 SkScalarRoundToInt(pt.fX),
2232 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002233 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002234 iter.fDevice->drawImage(image, x, y, pnt);
reed262a71b2015-12-05 13:07:27 -08002235 }
reeda85d4d02015-05-06 12:56:48 -07002236 }
halcanary9d524f22016-03-29 09:03:52 -07002237
reeda85d4d02015-05-06 12:56:48 -07002238 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002239}
2240
reed41af9662015-01-05 07:49:08 -08002241void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002242 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002243 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002244 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002245 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002246 if (paint) {
2247 paint->computeFastBounds(dst, &storage);
2248 }
2249 if (this->quickReject(storage)) {
2250 return;
2251 }
reeda85d4d02015-05-06 12:56:48 -07002252 }
2253 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002254 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002255 paint = lazy.init();
2256 }
halcanary9d524f22016-03-29 09:03:52 -07002257
senorblancoc41e7e12015-12-07 12:51:30 -08002258 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002259 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002260
reeda85d4d02015-05-06 12:56:48 -07002261 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002262 iter.fDevice->drawImageRect(image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002263 }
halcanary9d524f22016-03-29 09:03:52 -07002264
reeda85d4d02015-05-06 12:56:48 -07002265 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002266}
2267
reed41af9662015-01-05 07:49:08 -08002268void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002269 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002270 SkDEBUGCODE(bitmap.validate();)
2271
reed33366972015-10-08 09:22:02 -07002272 if (bitmap.drawsNothing()) {
2273 return;
2274 }
2275
2276 SkLazyPaint lazy;
2277 if (nullptr == paint) {
2278 paint = lazy.init();
2279 }
2280
Mike Reed822128b2017-02-28 16:41:03 -05002281 SkRect bounds;
2282 bitmap.getBounds(&bounds);
2283 bounds.offset(x, y);
2284 bool canFastBounds = paint->canComputeFastBounds();
2285 if (canFastBounds) {
2286 SkRect storage;
2287 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002288 return;
2289 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290 }
reed@google.com4b226022011-01-11 18:32:13 +00002291
reeda2217ef2016-07-20 06:04:34 -07002292 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002293 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2294 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002295 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002296 special = this->getDevice()->makeSpecial(bitmap);
2297 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002298 drawAsSprite = false;
2299 }
2300 }
2301
Mike Reed822128b2017-02-28 16:41:03 -05002302 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2303
2304 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002305
2306 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002307 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002308 if (special) {
reed262a71b2015-12-05 13:07:27 -08002309 SkPoint pt;
Mike Reeda1361362017-03-07 09:37:29 -05002310 iter.fDevice->ctm().mapXY(x, y, &pt);
2311 iter.fDevice->drawSpecial(special.get(),
reeda2217ef2016-07-20 06:04:34 -07002312 SkScalarRoundToInt(pt.fX),
2313 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002314 } else {
Mike Reeda1361362017-03-07 09:37:29 -05002315 iter.fDevice->drawBitmap(bitmap, matrix, looper.paint());
reed262a71b2015-12-05 13:07:27 -08002316 }
reed33366972015-10-08 09:22:02 -07002317 }
msarettfbfa2582016-08-12 08:29:08 -07002318
reed33366972015-10-08 09:22:02 -07002319 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002320}
2321
reed@google.com9987ec32011-09-07 11:57:52 +00002322// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002323void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002324 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002325 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002326 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002327 return;
2328 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002329
halcanary96fcdcc2015-08-27 07:41:13 -07002330 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002331 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002332 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2333 return;
2334 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002335 }
reed@google.com3d608122011-11-21 15:16:16 +00002336
reed@google.com33535f32012-09-25 15:37:50 +00002337 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002338 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002339 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002340 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002341
senorblancoc41e7e12015-12-07 12:51:30 -08002342 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002343 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002344
reed@google.com33535f32012-09-25 15:37:50 +00002345 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002346 iter.fDevice->drawBitmapRect(bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002347 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002348
reed@google.com33535f32012-09-25 15:37:50 +00002349 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002350}
2351
reed41af9662015-01-05 07:49:08 -08002352void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002353 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002354 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002355 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002356 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002357}
2358
reed4c21dc52015-06-25 12:32:03 -07002359void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2360 const SkPaint* paint) {
2361 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002362
halcanary96fcdcc2015-08-27 07:41:13 -07002363 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002364 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002365 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2366 return;
2367 }
reed@google.com3d608122011-11-21 15:16:16 +00002368 }
halcanary9d524f22016-03-29 09:03:52 -07002369
reed4c21dc52015-06-25 12:32:03 -07002370 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002371 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002372 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002373 }
halcanary9d524f22016-03-29 09:03:52 -07002374
senorblancoc41e7e12015-12-07 12:51:30 -08002375 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002376
reed4c21dc52015-06-25 12:32:03 -07002377 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002378 iter.fDevice->drawImageNine(image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002379 }
halcanary9d524f22016-03-29 09:03:52 -07002380
reed4c21dc52015-06-25 12:32:03 -07002381 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002382}
2383
reed41af9662015-01-05 07:49:08 -08002384void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2385 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002386 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002387 SkDEBUGCODE(bitmap.validate();)
2388
halcanary96fcdcc2015-08-27 07:41:13 -07002389 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002390 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002391 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2392 return;
2393 }
reed4c21dc52015-06-25 12:32:03 -07002394 }
halcanary9d524f22016-03-29 09:03:52 -07002395
reed4c21dc52015-06-25 12:32:03 -07002396 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002397 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002398 paint = lazy.init();
2399 }
halcanary9d524f22016-03-29 09:03:52 -07002400
senorblancoc41e7e12015-12-07 12:51:30 -08002401 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002402
reed4c21dc52015-06-25 12:32:03 -07002403 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002404 iter.fDevice->drawBitmapNine(bitmap, center, dst, looper.paint());
reed4c21dc52015-06-25 12:32:03 -07002405 }
halcanary9d524f22016-03-29 09:03:52 -07002406
reed4c21dc52015-06-25 12:32:03 -07002407 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002408}
2409
msarett16882062016-08-16 09:31:08 -07002410void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2411 const SkPaint* paint) {
2412 if (nullptr == paint || paint->canComputeFastBounds()) {
2413 SkRect storage;
2414 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2415 return;
2416 }
2417 }
2418
2419 SkLazyPaint lazy;
2420 if (nullptr == paint) {
2421 paint = lazy.init();
2422 }
2423
2424 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2425
2426 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002427 iter.fDevice->drawImageLattice(image, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002428 }
2429
2430 LOOPER_END
2431}
2432
2433void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2434 const SkRect& dst, const SkPaint* paint) {
2435 if (nullptr == paint || paint->canComputeFastBounds()) {
2436 SkRect storage;
2437 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2438 return;
2439 }
2440 }
2441
2442 SkLazyPaint lazy;
2443 if (nullptr == paint) {
2444 paint = lazy.init();
2445 }
2446
2447 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2448
2449 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002450 iter.fDevice->drawBitmapLattice(bitmap, lattice, dst, looper.paint());
msarett16882062016-08-16 09:31:08 -07002451 }
2452
2453 LOOPER_END
2454}
2455
reed@google.comf67e4cf2011-03-15 20:56:58 +00002456class SkDeviceFilteredPaint {
2457public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002458 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002459 uint32_t filteredFlags = device->filterTextFlags(paint);
2460 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002461 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002462 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002463 fPaint = newPaint;
2464 } else {
2465 fPaint = &paint;
2466 }
2467 }
2468
reed@google.comf67e4cf2011-03-15 20:56:58 +00002469 const SkPaint& paint() const { return *fPaint; }
2470
2471private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002472 const SkPaint* fPaint;
2473 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002474};
2475
reed@google.come0d9ce82014-04-23 04:00:17 +00002476void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2477 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002478 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002479
2480 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002481 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002482 iter.fDevice->drawText(text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002483 }
2484
reed@google.com4e2b3d32011-04-07 14:18:59 +00002485 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002486}
2487
reed@google.come0d9ce82014-04-23 04:00:17 +00002488void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2489 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002490 SkPoint textOffset = SkPoint::Make(0, 0);
2491
halcanary96fcdcc2015-08-27 07:41:13 -07002492 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002493
reed@android.com8a1c16f2008-12-17 15:59:43 +00002494 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002495 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002496 iter.fDevice->drawPosText(text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002497 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002498 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002499
reed@google.com4e2b3d32011-04-07 14:18:59 +00002500 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002501}
2502
reed@google.come0d9ce82014-04-23 04:00:17 +00002503void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2504 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002505
2506 SkPoint textOffset = SkPoint::Make(0, constY);
2507
halcanary96fcdcc2015-08-27 07:41:13 -07002508 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002509
reed@android.com8a1c16f2008-12-17 15:59:43 +00002510 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002511 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002512 iter.fDevice->drawPosText(text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002513 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002514 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002515
reed@google.com4e2b3d32011-04-07 14:18:59 +00002516 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002517}
2518
reed@google.come0d9ce82014-04-23 04:00:17 +00002519void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2520 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002521 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002522
reed@android.com8a1c16f2008-12-17 15:59:43 +00002523 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002524 iter.fDevice->drawTextOnPath(text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002525 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002526 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002527
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002528 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002529}
2530
reed45561a02016-07-07 12:47:17 -07002531void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2532 const SkRect* cullRect, const SkPaint& paint) {
2533 if (cullRect && this->quickReject(*cullRect)) {
2534 return;
2535 }
2536
2537 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2538
2539 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002540 iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint());
reed45561a02016-07-07 12:47:17 -07002541 }
2542
2543 LOOPER_END
2544}
2545
fmalita00d5c2c2014-08-21 08:53:26 -07002546void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2547 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002548
fmalita85d5eb92015-03-04 11:20:12 -08002549 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002550 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002551 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002552 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002553 SkRect tmp;
2554 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2555 return;
2556 }
2557 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002558 }
2559
fmalita024f9962015-03-03 19:08:17 -08002560 // We cannot filter in the looper as we normally do, because the paint is
2561 // incomplete at this point (text-related attributes are embedded within blob run paints).
2562 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002563 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002564
fmalita85d5eb92015-03-04 11:20:12 -08002565 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002566
fmalitaaa1b9122014-08-28 14:32:24 -07002567 while (iter.next()) {
2568 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
Mike Reeda1361362017-03-07 09:37:29 -05002569 iter.fDevice->drawTextBlob(blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002570 }
2571
fmalitaaa1b9122014-08-28 14:32:24 -07002572 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002573
2574 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002575}
2576
reed@google.come0d9ce82014-04-23 04:00:17 +00002577// These will become non-virtual, so they always call the (virtual) onDraw... method
2578void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2579 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002580 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002581 if (byteLength) {
2582 this->onDrawText(text, byteLength, x, y, paint);
2583 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002584}
2585void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2586 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002587 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002588 if (byteLength) {
2589 this->onDrawPosText(text, byteLength, pos, paint);
2590 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002591}
2592void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2593 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002594 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002595 if (byteLength) {
2596 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2597 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002598}
2599void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2600 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002601 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002602 if (byteLength) {
2603 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2604 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002605}
reed45561a02016-07-07 12:47:17 -07002606void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2607 const SkRect* cullRect, const SkPaint& paint) {
2608 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2609 if (byteLength) {
2610 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2611 }
2612}
fmalita00d5c2c2014-08-21 08:53:26 -07002613void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2614 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002615 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002616 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002617 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002618}
reed@google.come0d9ce82014-04-23 04:00:17 +00002619
reed41af9662015-01-05 07:49:08 -08002620void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2621 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002622 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002623 const uint16_t indices[], int indexCount,
2624 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002625 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002626 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002627
reed@android.com8a1c16f2008-12-17 15:59:43 +00002628 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002629 iter.fDevice->drawVertices(vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002630 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002631 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002632 }
reed@google.com4b226022011-01-11 18:32:13 +00002633
reed@google.com4e2b3d32011-04-07 14:18:59 +00002634 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002635}
2636
Brian Salomon199fb872017-02-06 09:41:10 -05002637void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode,
2638 const SkPaint& paint, uint32_t flags) {
2639 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2640 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2641
2642 while (iter.next()) {
2643 // In the common case of one iteration we could std::move vertices here.
Mike Reeda1361362017-03-07 09:37:29 -05002644 iter.fDevice->drawVerticesObject(vertices, bmode, looper.paint(), flags);
Brian Salomon199fb872017-02-06 09:41:10 -05002645 }
2646
2647 LOOPER_END
2648}
2649
2650void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode,
2651 const SkPaint& paint, uint32_t flags) {
2652 const SkPoint* texs =
2653 (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords();
2654 const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors();
2655 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs,
2656 colors, mode, vertices->indices(), vertices->indexCount(), paint);
2657}
2658
dandovb3c9d1c2014-08-12 08:34:29 -07002659void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002660 const SkPoint texCoords[4], SkBlendMode bmode,
2661 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002662 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002663 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002664 return;
2665 }
mtklein6cfa73a2014-08-13 13:33:49 -07002666
Mike Reedfaba3712016-11-03 14:45:31 -04002667 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002668}
2669
2670void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002671 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002672 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002673 // Since a patch is always within the convex hull of the control points, we discard it when its
2674 // bounding rectangle is completely outside the current clip.
2675 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002676 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002677 if (this->quickReject(bounds)) {
2678 return;
2679 }
mtklein6cfa73a2014-08-13 13:33:49 -07002680
halcanary96fcdcc2015-08-27 07:41:13 -07002681 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002682
dandovecfff212014-08-04 10:02:00 -07002683 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002684 iter.fDevice->drawPatch(cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002685 }
mtklein6cfa73a2014-08-13 13:33:49 -07002686
dandovecfff212014-08-04 10:02:00 -07002687 LOOPER_END
2688}
2689
reeda8db7282015-07-07 10:22:31 -07002690void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002691 RETURN_ON_NULL(dr);
2692 if (x || y) {
2693 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2694 this->onDrawDrawable(dr, &matrix);
2695 } else {
2696 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002697 }
2698}
2699
reeda8db7282015-07-07 10:22:31 -07002700void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002701 RETURN_ON_NULL(dr);
2702 if (matrix && matrix->isIdentity()) {
2703 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002704 }
reede3b38ce2016-01-08 09:18:44 -08002705 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002706}
2707
2708void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002709 // drawable bounds are no longer reliable (e.g. android displaylist)
2710 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002711 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002712}
2713
reed71c3c762015-06-24 10:29:17 -07002714void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002715 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002716 const SkRect* cull, const SkPaint* paint) {
2717 if (cull && this->quickReject(*cull)) {
2718 return;
2719 }
2720
2721 SkPaint pnt;
2722 if (paint) {
2723 pnt = *paint;
2724 }
halcanary9d524f22016-03-29 09:03:52 -07002725
halcanary96fcdcc2015-08-27 07:41:13 -07002726 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002727 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002728 iter.fDevice->drawAtlas(atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002729 }
2730 LOOPER_END
2731}
2732
reedf70b5312016-03-04 16:36:20 -08002733void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2734 SkASSERT(key);
2735
2736 SkPaint paint;
2737 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2738 while (iter.next()) {
Mike Reeda1361362017-03-07 09:37:29 -05002739 iter.fDevice->drawAnnotation(rect, key, value);
reedf70b5312016-03-04 16:36:20 -08002740 }
2741 LOOPER_END
2742}
2743
reed@android.com8a1c16f2008-12-17 15:59:43 +00002744//////////////////////////////////////////////////////////////////////////////
2745// These methods are NOT virtual, and therefore must call back into virtual
2746// methods, rather than actually drawing themselves.
2747//////////////////////////////////////////////////////////////////////////////
2748
Mike Reed3661bc92017-02-22 13:21:42 -05002749#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed374772b2016-10-05 17:33:02 -07002750void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002751 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002752 SkPaint paint;
2753
2754 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002755 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002756 this->drawPaint(paint);
2757}
Mike Reed3661bc92017-02-22 13:21:42 -05002758#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002759
reed374772b2016-10-05 17:33:02 -07002760void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002761 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762 SkPaint paint;
2763
2764 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002765 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766 this->drawPaint(paint);
2767}
2768
2769void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002770 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002771 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2773}
2774
Mike Reed3661bc92017-02-22 13:21:42 -05002775#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002777 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002778 SkPoint pt;
2779 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002780
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 pt.set(x, y);
2782 paint.setColor(color);
2783 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2784}
Mike Reed3661bc92017-02-22 13:21:42 -05002785#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786
Mike Reed3661bc92017-02-22 13:21:42 -05002787void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002788 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002789 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002790
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791 pts[0].set(x0, y0);
2792 pts[1].set(x1, y1);
2793 this->drawPoints(kLines_PointMode, 2, pts, paint);
2794}
2795
Mike Reed3661bc92017-02-22 13:21:42 -05002796#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002797void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2798 SkScalar right, SkScalar bottom,
2799 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002800 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002801 SkRect r;
2802
2803 r.set(left, top, right, bottom);
2804 this->drawRect(r, paint);
2805}
Mike Reed3661bc92017-02-22 13:21:42 -05002806#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807
Mike Reed3661bc92017-02-22 13:21:42 -05002808void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002809 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002810 if (radius < 0) {
2811 radius = 0;
2812 }
2813
2814 SkRect r;
2815 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002816 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817}
2818
2819void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2820 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002821 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002822 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002823 SkRRect rrect;
2824 rrect.setRectXY(r, rx, ry);
2825 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826 } else {
2827 this->drawRect(r, paint);
2828 }
2829}
2830
reed@android.com8a1c16f2008-12-17 15:59:43 +00002831void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2832 SkScalar sweepAngle, bool useCenter,
2833 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002834 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07002835 if (oval.isEmpty() || !sweepAngle) {
2836 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837 }
bsalomon21af9ca2016-08-25 12:29:23 -07002838 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002839}
2840
2841void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2842 const SkPath& path, SkScalar hOffset,
2843 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002844 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002845 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002846
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847 matrix.setTranslate(hOffset, vOffset);
2848 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2849}
2850
reed@android.comf76bacf2009-05-13 14:00:33 +00002851///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002852
2853/**
2854 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2855 * against the playback cost of recursing into the subpicture to get at its actual ops.
2856 *
2857 * For now we pick a conservatively small value, though measurement (and other heuristics like
2858 * the type of ops contained) may justify changing this value.
2859 */
2860#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002861
reedd5fa1a42014-08-09 11:08:05 -07002862void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002863 RETURN_ON_NULL(picture);
2864
reed1c2c4412015-04-30 13:09:24 -07002865 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08002866 if (matrix && matrix->isIdentity()) {
2867 matrix = nullptr;
2868 }
2869 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2870 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2871 picture->playback(this);
2872 } else {
2873 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07002874 }
2875}
robertphillips9b14f262014-06-04 05:40:44 -07002876
reedd5fa1a42014-08-09 11:08:05 -07002877void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2878 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002879 if (!paint || paint->canComputeFastBounds()) {
2880 SkRect bounds = picture->cullRect();
2881 if (paint) {
2882 paint->computeFastBounds(bounds, &bounds);
2883 }
2884 if (matrix) {
2885 matrix->mapRect(&bounds);
2886 }
2887 if (this->quickReject(bounds)) {
2888 return;
2889 }
2890 }
2891
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002892 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002893 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002894}
2895
vjiaoblack95302da2016-07-21 10:25:54 -07002896#ifdef SK_EXPERIMENTAL_SHADOWING
2897void SkCanvas::drawShadowedPicture(const SkPicture* picture,
2898 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002899 const SkPaint* paint,
2900 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07002901 RETURN_ON_NULL(picture);
2902
2903 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
2904
vjiaoblacke6f5d562016-08-25 06:30:23 -07002905 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07002906}
2907
2908void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
2909 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07002910 const SkPaint* paint,
2911 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07002912 if (!paint || paint->canComputeFastBounds()) {
2913 SkRect bounds = picture->cullRect();
2914 if (paint) {
2915 paint->computeFastBounds(bounds, &bounds);
2916 }
2917 if (matrix) {
2918 matrix->mapRect(&bounds);
2919 }
2920 if (this->quickReject(bounds)) {
2921 return;
2922 }
2923 }
2924
2925 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2926
vjiaoblacke6f5d562016-08-25 06:30:23 -07002927 sk_sp<SkImage> povDepthMap;
2928 sk_sp<SkImage> diffuseMap;
2929
vjiaoblack904527d2016-08-09 09:32:09 -07002930 // povDepthMap
2931 {
2932 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07002933 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
2934 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07002935 sk_sp<SkLights> povLight = builder.finish();
2936
2937 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2938 picture->cullRect().height(),
2939 kBGRA_8888_SkColorType,
2940 kOpaque_SkAlphaType);
2941
2942 // Create a new surface (that matches the backend of canvas)
2943 // to create the povDepthMap
2944 sk_sp<SkSurface> surf(this->makeSurface(info));
2945
2946 // Wrap another SPFCanvas around the surface
2947 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
2948 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
2949
2950 // set the depth map canvas to have the light as the user's POV
2951 depthMapCanvas->setLights(std::move(povLight));
2952
2953 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07002954 povDepthMap = surf->makeImageSnapshot();
2955 }
2956
2957 // diffuseMap
2958 {
2959 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
2960 picture->cullRect().height(),
2961 kBGRA_8888_SkColorType,
2962 kOpaque_SkAlphaType);
2963
2964 sk_sp<SkSurface> surf(this->makeSurface(info));
2965 surf->getCanvas()->drawPicture(picture);
2966
2967 diffuseMap = surf->makeImageSnapshot();
2968 }
vjiaoblack904527d2016-08-09 09:32:09 -07002969
2970 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
2971 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07002972 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
2973 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07002974
2975 // TODO: pass the depth to the shader in vertices, or uniforms
2976 // so we don't have to render depth and color separately
2977 for (int i = 0; i < fLights->numLights(); ++i) {
2978 // skip over ambient lights; they don't cast shadows
2979 // lights that have shadow maps do not need updating (because lights are immutable)
2980 sk_sp<SkImage> depthMap;
2981 SkISize shMapSize;
2982
2983 if (fLights->light(i).getShadowMap() != nullptr) {
2984 continue;
2985 }
2986
2987 if (fLights->light(i).isRadial()) {
2988 shMapSize.fHeight = 1;
2989 shMapSize.fWidth = (int) picture->cullRect().width();
2990
2991 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
2992 kBGRA_8888_SkColorType,
2993 kOpaque_SkAlphaType);
2994
2995 // Create new surface (that matches the backend of canvas)
2996 // for each shadow map
2997 sk_sp<SkSurface> surf(this->makeSurface(info));
2998
2999 // Wrap another SPFCanvas around the surface
3000 SkCanvas* depthMapCanvas = surf->getCanvas();
3001
3002 SkLights::Builder builder;
3003 builder.add(fLights->light(i));
3004 sk_sp<SkLights> curLight = builder.finish();
3005
3006 sk_sp<SkShader> shadowMapShader;
3007 shadowMapShader = SkRadialShadowMapShader::Make(
3008 povDepthShader, curLight,
3009 (int) picture->cullRect().width(),
3010 (int) picture->cullRect().height());
3011
3012 SkPaint shadowMapPaint;
3013 shadowMapPaint.setShader(std::move(shadowMapShader));
3014
3015 depthMapCanvas->setLights(curLight);
3016
3017 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3018 diffuseMap->height()),
3019 shadowMapPaint);
3020
3021 depthMap = surf->makeImageSnapshot();
3022
3023 } else {
3024 // TODO: compute the correct size of the depth map from the light properties
3025 // TODO: maybe add a kDepth_8_SkColorType
3026 // TODO: find actual max depth of picture
3027 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3028 fLights->light(i), 255,
3029 (int) picture->cullRect().width(),
3030 (int) picture->cullRect().height());
3031
3032 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3033 kBGRA_8888_SkColorType,
3034 kOpaque_SkAlphaType);
3035
3036 // Create a new surface (that matches the backend of canvas)
3037 // for each shadow map
3038 sk_sp<SkSurface> surf(this->makeSurface(info));
3039
3040 // Wrap another SPFCanvas around the surface
3041 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3042 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3043 depthMapCanvas->setShadowParams(params);
3044
3045 // set the depth map canvas to have the light we're drawing.
3046 SkLights::Builder builder;
3047 builder.add(fLights->light(i));
3048 sk_sp<SkLights> curLight = builder.finish();
3049 depthMapCanvas->setLights(std::move(curLight));
3050
3051 depthMapCanvas->drawPicture(picture);
3052 depthMap = surf->makeImageSnapshot();
3053 }
3054
3055 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3056 fLights->light(i).setShadowMap(std::move(depthMap));
3057 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3058 // we blur the variance map
3059 SkPaint blurPaint;
3060 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3061 params.fShadowRadius, nullptr));
3062
3063 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3064 kBGRA_8888_SkColorType,
3065 kOpaque_SkAlphaType);
3066
3067 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3068
3069 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3070
3071 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3072 }
3073 }
3074
3075 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003076 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3077 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003078 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003079 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003080 diffuseMap->height(),
3081 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003082
3083 shadowPaint.setShader(shadowShader);
3084
3085 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003086}
3087#endif
3088
reed@android.com8a1c16f2008-12-17 15:59:43 +00003089///////////////////////////////////////////////////////////////////////////////
3090///////////////////////////////////////////////////////////////////////////////
3091
reed3aafe112016-08-18 12:45:34 -07003092SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003093 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003094
3095 SkASSERT(canvas);
3096
reed3aafe112016-08-18 12:45:34 -07003097 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003098 fDone = !fImpl->next();
3099}
3100
3101SkCanvas::LayerIter::~LayerIter() {
3102 fImpl->~SkDrawIter();
3103}
3104
3105void SkCanvas::LayerIter::next() {
3106 fDone = !fImpl->next();
3107}
3108
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003109SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003110 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003111}
3112
3113const SkMatrix& SkCanvas::LayerIter::matrix() const {
Mike Reeda1361362017-03-07 09:37:29 -05003114 return fImpl->fDevice->ctm();
reed@android.com8a1c16f2008-12-17 15:59:43 +00003115}
3116
3117const SkPaint& SkCanvas::LayerIter::paint() const {
3118 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003119 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003120 paint = &fDefaultPaint;
3121 }
3122 return *paint;
3123}
3124
Mike Reeda1361362017-03-07 09:37:29 -05003125void SkCanvas::LayerIter::clip(SkRegion* rgn) const {
3126 return fImpl->fDevice->onAsRgnClip(rgn);
3127}
3128
reed@android.com8a1c16f2008-12-17 15:59:43 +00003129int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3130int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003131
3132///////////////////////////////////////////////////////////////////////////////
3133
fmalitac3b589a2014-06-05 12:40:07 -07003134SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003135
3136///////////////////////////////////////////////////////////////////////////////
3137
3138static bool supported_for_raster_canvas(const SkImageInfo& info) {
3139 switch (info.alphaType()) {
3140 case kPremul_SkAlphaType:
3141 case kOpaque_SkAlphaType:
3142 break;
3143 default:
3144 return false;
3145 }
3146
3147 switch (info.colorType()) {
3148 case kAlpha_8_SkColorType:
3149 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003150 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003151 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003152 break;
3153 default:
3154 return false;
3155 }
3156
3157 return true;
3158}
3159
Mike Reed5df49342016-11-12 08:06:55 -06003160std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3161 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003162 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003163 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003164 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003165
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003166 SkBitmap bitmap;
3167 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003168 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003169 }
Mike Reed5df49342016-11-12 08:06:55 -06003170 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003171}
reedd5fa1a42014-08-09 11:08:05 -07003172
3173///////////////////////////////////////////////////////////////////////////////
3174
3175SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003176 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003177 : fCanvas(canvas)
3178 , fSaveCount(canvas->getSaveCount())
3179{
bsalomon49f085d2014-09-05 13:34:00 -07003180 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003181 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003182 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003183 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003184 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003185 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003186 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003187 canvas->save();
3188 }
mtklein6cfa73a2014-08-13 13:33:49 -07003189
bsalomon49f085d2014-09-05 13:34:00 -07003190 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003191 canvas->concat(*matrix);
3192 }
3193}
3194
3195SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3196 fCanvas->restoreToCount(fSaveCount);
3197}
reede8f30622016-03-23 18:59:25 -07003198
Florin Malitaee424ac2016-12-01 12:47:59 -05003199///////////////////////////////////////////////////////////////////////////////
3200
3201SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3202 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3203
Florin Malita439ace92016-12-02 12:05:41 -05003204SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3205 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3206
Florin Malitaee424ac2016-12-01 12:47:59 -05003207SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3208 (void)this->INHERITED::getSaveLayerStrategy(rec);
3209 return kNoLayer_SaveLayerStrategy;
3210}
3211
3212///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003213
reed73603f32016-09-20 08:42:38 -07003214static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3215static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3216static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3217static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3218static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3219static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003220
3221///////////////////////////////////////////////////////////////////////////////////////////////////
3222
3223SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3224 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3225 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3226 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3227 SkIPoint origin = dev->getOrigin();
3228 SkMatrix ctm = this->getTotalMatrix();
3229 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3230
3231 SkIRect clip = fMCRec->fRasterClip.getBounds();
3232 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003233 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003234 clip.setEmpty();
3235 }
3236
3237 fAllocator->updateHandle(handle, ctm, clip);
3238 return handle;
3239 }
3240 return nullptr;
3241}
3242
3243static bool install(SkBitmap* bm, const SkImageInfo& info,
3244 const SkRasterHandleAllocator::Rec& rec) {
3245 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3246 rec.fReleaseProc, rec.fReleaseCtx);
3247}
3248
3249SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3250 SkBitmap* bm) {
3251 SkRasterHandleAllocator::Rec rec;
3252 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3253 return nullptr;
3254 }
3255 return rec.fHandle;
3256}
3257
3258std::unique_ptr<SkCanvas>
3259SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3260 const SkImageInfo& info, const Rec* rec) {
3261 if (!alloc || !supported_for_raster_canvas(info)) {
3262 return nullptr;
3263 }
3264
3265 SkBitmap bm;
3266 Handle hndl;
3267
3268 if (rec) {
3269 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3270 } else {
3271 hndl = alloc->allocBitmap(info, &bm);
3272 }
3273 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3274}