blob: cbf40f15568590dc29882f3139d214df54850a32 [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());
78 if (!this->getClipStack()->quickContains(bounds)) {
79 return false;
80 }
81
82 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070083 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070084 return false; // conservative
85 }
halcanaryc5769b22016-08-10 07:13:21 -070086
87 SkRect devRect;
88 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
89 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070090 return false;
91 }
92 }
93
94 if (paint) {
95 SkPaint::Style paintStyle = paint->getStyle();
96 if (!(paintStyle == SkPaint::kFill_Style ||
97 paintStyle == SkPaint::kStrokeAndFill_Style)) {
98 return false;
99 }
100 if (paint->getMaskFilter() || paint->getLooper()
101 || paint->getPathEffect() || paint->getImageFilter()) {
102 return false; // conservative
103 }
104 }
105 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
106}
107
108///////////////////////////////////////////////////////////////////////////////////////////////////
109
reedd990e2f2014-12-22 11:58:30 -0800110static bool gIgnoreSaveLayerBounds;
111void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
112 gIgnoreSaveLayerBounds = ignore;
113}
114bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
115 return gIgnoreSaveLayerBounds;
116}
117
reed0acf1b42014-12-22 16:12:38 -0800118static bool gTreatSpriteAsBitmap;
119void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
120 gTreatSpriteAsBitmap = spriteAsBitmap;
121}
122bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
123 return gTreatSpriteAsBitmap;
124}
125
reed@google.comda17f752012-08-16 18:27:05 +0000126// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127//#define SK_TRACE_SAVERESTORE
128
129#ifdef SK_TRACE_SAVERESTORE
130 static int gLayerCounter;
131 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
132 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
133
134 static int gRecCounter;
135 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
136 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
137
138 static int gCanvasCounter;
139 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
140 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
141#else
142 #define inc_layer()
143 #define dec_layer()
144 #define inc_rec()
145 #define dec_rec()
146 #define inc_canvas()
147 #define dec_canvas()
148#endif
149
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000150typedef SkTLazy<SkPaint> SkLazyPaint;
151
reedc83a2972015-07-16 07:40:45 -0700152void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000153 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700154 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
155 ? SkSurface::kDiscard_ContentChangeMode
156 : SkSurface::kRetain_ContentChangeMode);
157 }
158}
159
160void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
161 ShaderOverrideOpacity overrideOpacity) {
162 if (fSurfaceBase) {
163 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
164 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
165 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
166 // and therefore we don't care which mode we're in.
167 //
168 if (fSurfaceBase->outstandingImageSnapshot()) {
169 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
170 mode = SkSurface::kDiscard_ContentChangeMode;
171 }
172 }
173 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000174 }
175}
176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000179/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 The clip/matrix/proc are fields that reflect the top of the save/restore
181 stack. Whenever the canvas changes, it marks a dirty flag, and then before
182 these are used (assuming we're not on a layer) we rebuild these cache
183 values: they reflect the top of the save stack, but translated and clipped
184 by the device's XY offset and bitmap-bounds.
185*/
186struct DeviceCM {
187 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000188 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000189 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000190 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700191 const SkMatrix* fMatrix;
192 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700193 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194
reed96e657d2015-03-10 17:30:07 -0700195 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700196 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700197 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700198 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700199 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700200 {
reed2c9e2002016-07-25 08:05:22 -0700201 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000202 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700203 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000204 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000206 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700207 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700208 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000209 }
reed@google.com4b226022011-01-11 18:32:13 +0000210
mtkleinfeaadee2015-04-08 11:25:48 -0700211 void reset(const SkIRect& bounds) {
212 SkASSERT(!fPaint);
213 SkASSERT(!fNext);
214 SkASSERT(fDevice);
215 fClip.setRect(bounds);
216 }
217
reed@google.com045e62d2011-10-24 12:19:46 +0000218 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700219 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000220 int x = fDevice->getOrigin().x();
221 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 int width = fDevice->width();
223 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000224
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 if ((x | y) == 0) {
226 fMatrix = &totalMatrix;
227 fClip = totalClip;
228 } else {
229 fMatrixStorage = totalMatrix;
230 fMatrixStorage.postTranslate(SkIntToScalar(-x),
231 SkIntToScalar(-y));
232 fMatrix = &fMatrixStorage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 totalClip.translate(-x, -y, &fClip);
234 }
235
reed@google.com045e62d2011-10-24 12:19:46 +0000236 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
Mike Reedc42a1cd2017-02-14 14:25:14 -0500238#ifdef SK_USE_DEVICE_CLIPPING
239 SkASSERT(*fMatrix == fDevice->ctm());
240 // TODO: debug tiles-rt-8888 so we can enable this all the time
241// fDevice->validateDevBounds(fClip.getBounds());
242#endif
243
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000247 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248 SkRegion::kDifference_Op);
249 }
reed@google.com4b226022011-01-11 18:32:13 +0000250
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251#ifdef SK_DEBUG
252 if (!fClip.isEmpty()) {
253 SkIRect deviceR;
254 deviceR.set(0, 0, width, height);
255 SkASSERT(deviceR.contains(fClip.getBounds()));
256 }
257#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000258 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259};
260
261/* This is the record we keep for each save/restore level in the stack.
262 Since a level optionally copies the matrix and/or stack, we have pointers
263 for these fields. If the value is copied for this level, the copy is
264 stored in the ...Storage field, and the pointer points to that. If the
265 value is not copied for this level, we ignore ...Storage, and just point
266 at the corresponding value in the previous level in the stack.
267*/
268class SkCanvas::MCRec {
269public:
reed1f836ee2014-07-07 07:49:34 -0700270 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700271 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 /* If there are any layers in the stack, this points to the top-most
273 one that is at or below this level in the stack (so we know what
274 bitmap/device to draw into from this level. This value is NOT
275 reference counted, since the real owner is either our fLayer field,
276 or a previous one in a lower level.)
277 */
reed2ff1fce2014-12-11 07:07:37 -0800278 DeviceCM* fTopLayer;
279 SkRasterClip fRasterClip;
280 SkMatrix fMatrix;
281 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282
vjiaoblacke5de1302016-07-13 14:05:28 -0700283 // This is the current cumulative depth (aggregate of all done translateZ calls)
284 SkScalar fCurDrawDepth;
285
reedd9544982014-09-09 18:46:22 -0700286 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700287 fFilter = nullptr;
288 fLayer = nullptr;
289 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800290 fMatrix.reset();
291 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700292 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700293
reedd9544982014-09-09 18:46:22 -0700294 // don't bother initializing fNext
295 inc_rec();
296 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700297 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
298 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700299 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700300 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700301 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800302 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700303
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 // don't bother initializing fNext
305 inc_rec();
306 }
307 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000308 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700309 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310 dec_rec();
311 }
mtkleinfeaadee2015-04-08 11:25:48 -0700312
313 void reset(const SkIRect& bounds) {
314 SkASSERT(fLayer);
315 SkASSERT(fDeferredSaveCount == 0);
316
317 fMatrix.reset();
318 fRasterClip.setRect(bounds);
319 fLayer->reset(bounds);
320 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321};
322
reed02f9ed72016-09-06 09:06:18 -0700323static SkIRect compute_device_bounds(SkBaseDevice* device) {
324 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
325 device->width(), device->height());
326}
327
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328class SkDrawIter : public SkDraw {
329public:
reed3aafe112016-08-18 12:45:34 -0700330 SkDrawIter(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 canvas->updateDeviceCMCache();
332
bungeman6bd52842016-10-27 09:30:08 -0700333 fClipStack = canvas->getClipStack();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700335
336 fMultiDeviceCS = nullptr;
337 if (fCurrLayer->fNext) {
bungeman6bd52842016-10-27 09:30:08 -0700338 fMultiDeviceCS = canvas->fClipStack.get();
reed02f9ed72016-09-06 09:06:18 -0700339 fMultiDeviceCS->save();
340 }
Mike Reedd519d482017-02-16 11:04:52 -0500341#ifdef SK_USE_DEVICE_CLIPPING
342 fClipStack = nullptr; // for testing
343#endif
reed02f9ed72016-09-06 09:06:18 -0700344 }
345
346 ~SkDrawIter() {
347 if (fMultiDeviceCS) {
348 fMultiDeviceCS->restore();
349 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 }
reed@google.com4b226022011-01-11 18:32:13 +0000351
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700353 if (fMultiDeviceCS && fDevice) {
354 // remove the previous device's bounds
Mike Reedc1f77742016-12-09 09:00:50 -0500355 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), kDifference_SkClipOp);
reed02f9ed72016-09-06 09:06:18 -0700356 }
357
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700359 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
360 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 }
362
reed@google.comf68c5e22012-02-24 16:38:58 +0000363 const DeviceCM* rec = fCurrLayer;
364 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365
366 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000367 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700369 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700370 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700371 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000373 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374
375 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700376 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000377
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 return true;
379 }
380 return false;
381 }
reed@google.com4b226022011-01-11 18:32:13 +0000382
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000383 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700384 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000385 int getX() const { return fDevice->getOrigin().x(); }
386 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000387 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000389
reed@android.com8a1c16f2008-12-17 15:59:43 +0000390private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000391 const DeviceCM* fCurrLayer;
392 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700393 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000394
395 typedef SkDraw INHERITED;
396};
397
Mike Reed7627fa52017-02-08 10:07:53 -0500398#define FOR_EACH_TOP_DEVICE( code ) \
399 do { \
400 DeviceCM* layer = fMCRec->fTopLayer; \
401 while (layer) { \
402 SkBaseDevice* device = layer->fDevice; \
Mike Reedc42a1cd2017-02-14 14:25:14 -0500403 if (device) { \
404 code; \
405 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500406 layer = layer->fNext; \
407 } \
408 } while (0)
409
reed@android.com8a1c16f2008-12-17 15:59:43 +0000410/////////////////////////////////////////////////////////////////////////////
411
reeddbc3cef2015-04-29 12:18:57 -0700412static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
413 return lazy->isValid() ? lazy->get() : lazy->set(orig);
414}
415
416/**
417 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700418 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700419 */
reedd053ce92016-03-22 10:17:23 -0700420static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700421 SkImageFilter* imgf = paint.getImageFilter();
422 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700423 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700424 }
425
reedd053ce92016-03-22 10:17:23 -0700426 SkColorFilter* imgCFPtr;
427 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700428 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700429 }
reedd053ce92016-03-22 10:17:23 -0700430 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700431
432 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700433 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700434 // there is no existing paint colorfilter, so we can just return the imagefilter's
435 return imgCF;
436 }
437
438 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
439 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700440 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700441}
442
senorblanco87e066e2015-10-28 11:23:36 -0700443/**
444 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
445 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
446 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
447 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
448 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
449 * conservative "effective" bounds based on the settings in the paint... with one exception. This
450 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
451 * deliberately ignored.
452 */
453static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
454 const SkRect& rawBounds,
455 SkRect* storage) {
456 SkPaint tmpUnfiltered(paint);
457 tmpUnfiltered.setImageFilter(nullptr);
458 if (tmpUnfiltered.canComputeFastBounds()) {
459 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
460 } else {
461 return rawBounds;
462 }
463}
464
reed@android.com8a1c16f2008-12-17 15:59:43 +0000465class AutoDrawLooper {
466public:
senorblanco87e066e2015-10-28 11:23:36 -0700467 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
468 // paint. It's used to determine the size of the offscreen layer for filters.
469 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700470 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700471 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000472 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800473#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000474 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800475#else
476 fFilter = nullptr;
477#endif
reed4a8126e2014-09-22 07:29:03 -0700478 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000479 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700480 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000481 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000482
reedd053ce92016-03-22 10:17:23 -0700483 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700484 if (simplifiedCF) {
485 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700486 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700487 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700488 fPaint = paint;
489 }
490
491 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700492 /**
493 * We implement ImageFilters for a given draw by creating a layer, then applying the
494 * imagefilter to the pixels of that layer (its backing surface/image), and then
495 * we call restore() to xfer that layer to the main canvas.
496 *
497 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
498 * 2. Generate the src pixels:
499 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
500 * return (fPaint). We then draw the primitive (using srcover) into a cleared
501 * buffer/surface.
502 * 3. Restore the layer created in #1
503 * The imagefilter is passed the buffer/surface from the layer (now filled with the
504 * src pixels of the primitive). It returns a new "filtered" buffer, which we
505 * draw onto the previous layer using the xfermode from the original paint.
506 */
reed@google.com8926b162012-03-23 15:36:36 +0000507 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500508 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700509 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700510 SkRect storage;
511 if (rawBounds) {
512 // Make rawBounds include all paint outsets except for those due to image filters.
513 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
514 }
reedbfd5f172016-01-07 11:28:08 -0800515 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700516 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700517 fTempLayerForImageFilter = true;
518 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000519 }
520
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000521 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500522 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000523 fIsSimple = false;
524 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700525 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000526 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700527 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000528 }
529 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000530
reed@android.com8a1c16f2008-12-17 15:59:43 +0000531 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700532 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000533 fCanvas->internalRestore();
534 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000535 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000536 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000537
reed@google.com4e2b3d32011-04-07 14:18:59 +0000538 const SkPaint& paint() const {
539 SkASSERT(fPaint);
540 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000541 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000542
reed@google.com129ec222012-05-15 13:24:09 +0000543 bool next(SkDrawFilter::Type drawType) {
544 if (fDone) {
545 return false;
546 } else if (fIsSimple) {
547 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000548 return !fPaint->nothingToDraw();
549 } else {
550 return this->doNext(drawType);
551 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000552 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000553
reed@android.com8a1c16f2008-12-17 15:59:43 +0000554private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500555 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700556 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000557 SkCanvas* fCanvas;
558 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000559 SkDrawFilter* fFilter;
560 const SkPaint* fPaint;
561 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700562 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000563 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000564 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000565 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500566 char fStorage[48];
567 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000568
569 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000570};
571
reed@google.com129ec222012-05-15 13:24:09 +0000572bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700573 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000574 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700575 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000576
reeddbc3cef2015-04-29 12:18:57 -0700577 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
578 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000579
reed5c476fb2015-04-20 08:04:21 -0700580 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700581 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700582 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000583 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000584
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000585 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000586 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000587 return false;
588 }
589 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000590 if (!fFilter->filter(paint, drawType)) {
591 fDone = true;
592 return false;
593 }
halcanary96fcdcc2015-08-27 07:41:13 -0700594 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000595 // no looper means we only draw once
596 fDone = true;
597 }
598 }
599 fPaint = paint;
600
601 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000602 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000603 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000604 }
605
606 // call this after any possible paint modifiers
607 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700608 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000609 return false;
610 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000611 return true;
612}
613
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614////////// macros to place around the internal draw calls //////////////////
615
reed3aafe112016-08-18 12:45:34 -0700616#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
617 this->predrawNotify(); \
618 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
619 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800620 SkDrawIter iter(this);
621
622
reed@google.com8926b162012-03-23 15:36:36 +0000623#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000624 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700625 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000626 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000627 SkDrawIter iter(this);
628
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000629#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000630 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700631 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000632 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000633 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000634
reedc83a2972015-07-16 07:40:45 -0700635#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
636 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700637 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700638 while (looper.next(type)) { \
639 SkDrawIter iter(this);
640
reed@google.com4e2b3d32011-04-07 14:18:59 +0000641#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642
643////////////////////////////////////////////////////////////////////////////
644
msarettfbfa2582016-08-12 08:29:08 -0700645static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
646 if (bounds.isEmpty()) {
647 return SkRect::MakeEmpty();
648 }
649
650 // Expand bounds out by 1 in case we are anti-aliasing. We store the
651 // bounds as floats to enable a faster quick reject implementation.
652 SkRect dst;
653 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
654 return dst;
655}
656
mtkleinfeaadee2015-04-08 11:25:48 -0700657void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
658 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700659 fClipStack->reset();
660 fMCRec->reset(bounds);
661
662 // We're peering through a lot of structs here. Only at this scope do we
663 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
664 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700665 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700666 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700667}
668
reedd9544982014-09-09 18:46:22 -0700669SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800670 if (device && device->forceConservativeRasterClip()) {
671 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
672 }
673 // Since init() is only called once by our constructors, it is safe to perform this
674 // const-cast.
675 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
676
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000677 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700678 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800679 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700680 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700681#ifdef SK_EXPERIMENTAL_SHADOWING
682 fLights = nullptr;
683#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684
halcanary385fe4d2015-08-26 13:07:48 -0700685 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700686
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700688 new (fMCRec) MCRec(fConservativeRasterClip);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500689 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700690 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691
reeda499f902015-05-01 09:34:31 -0700692 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
693 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700694 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700695 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700696
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000698
halcanary96fcdcc2015-08-27 07:41:13 -0700699 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000700
reedf92c8662014-08-18 08:02:43 -0700701 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700702 // The root device and the canvas should always have the same pixel geometry
703 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700704 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800705 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700706 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500707
708#ifdef SK_USE_DEVICE_CLIPPING
709 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
710#endif
reedf92c8662014-08-18 08:02:43 -0700711 }
msarettfbfa2582016-08-12 08:29:08 -0700712
reedf92c8662014-08-18 08:02:43 -0700713 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000714}
715
reed@google.comcde92112011-07-06 20:00:52 +0000716SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000717 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700718 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800719 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000720{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000721 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000722
halcanary96fcdcc2015-08-27 07:41:13 -0700723 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000724}
725
reedd9544982014-09-09 18:46:22 -0700726static SkBitmap make_nopixels(int width, int height) {
727 SkBitmap bitmap;
728 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
729 return bitmap;
730}
731
732class SkNoPixelsBitmapDevice : public SkBitmapDevice {
733public:
robertphillipsfcf78292015-06-19 11:49:52 -0700734 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
735 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800736 {
Mike Reedc42a1cd2017-02-14 14:25:14 -0500737 this->setOrigin(SkMatrix::I(), bounds.x(), bounds.y());
reed78e27682014-11-19 08:04:34 -0800738 }
reedd9544982014-09-09 18:46:22 -0700739
740private:
piotaixrb5fae932014-09-24 13:03:30 -0700741
reedd9544982014-09-09 18:46:22 -0700742 typedef SkBitmapDevice INHERITED;
743};
744
reed96a857e2015-01-25 10:33:58 -0800745SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000746 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800747 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800748 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000749{
750 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700751
halcanary385fe4d2015-08-26 13:07:48 -0700752 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
753 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700754}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000755
reed78e27682014-11-19 08:04:34 -0800756SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700757 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700758 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800759 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700760{
761 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700762
halcanary385fe4d2015-08-26 13:07:48 -0700763 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700764}
765
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000766SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000767 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700768 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800769 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000770{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700772
reedd9544982014-09-09 18:46:22 -0700773 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000774}
775
robertphillipsfcf78292015-06-19 11:49:52 -0700776SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
777 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700778 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800779 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700780{
781 inc_canvas();
782
783 this->init(device, flags);
784}
785
reed4a8126e2014-09-22 07:29:03 -0700786SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700787 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700788 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800789 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700790{
791 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700792
Hal Canary704cd322016-11-07 14:13:52 -0500793 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
794 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700795}
reed29c857d2014-09-21 10:25:07 -0700796
Mike Reed356f7c22017-01-10 11:58:39 -0500797SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
798 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700799 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
800 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500801 , fAllocator(std::move(alloc))
reed42b73eb2015-11-20 13:42:42 -0800802 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700803{
804 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700805
Mike Reed356f7c22017-01-10 11:58:39 -0500806 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500807 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000808}
809
Mike Reed356f7c22017-01-10 11:58:39 -0500810SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
811
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812SkCanvas::~SkCanvas() {
813 // free up the contents of our deque
814 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000815
reed@android.com8a1c16f2008-12-17 15:59:43 +0000816 this->internalRestore(); // restore the last, since we're going away
817
halcanary385fe4d2015-08-26 13:07:48 -0700818 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000819
reed@android.com8a1c16f2008-12-17 15:59:43 +0000820 dec_canvas();
821}
822
fmalita53d9f1c2016-01-25 06:23:54 -0800823#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824SkDrawFilter* SkCanvas::getDrawFilter() const {
825 return fMCRec->fFilter;
826}
827
828SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700829 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000830 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
831 return filter;
832}
fmalita77650002016-01-21 18:47:11 -0800833#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000834
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000835SkMetaData& SkCanvas::getMetaData() {
836 // metadata users are rare, so we lazily allocate it. If that changes we
837 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700838 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000839 fMetaData = new SkMetaData;
840 }
841 return *fMetaData;
842}
843
reed@android.com8a1c16f2008-12-17 15:59:43 +0000844///////////////////////////////////////////////////////////////////////////////
845
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000846void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700847 this->onFlush();
848}
849
850void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000851 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000852 if (device) {
853 device->flush();
854 }
855}
856
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000857SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000858 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000859 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
860}
861
senorblancoafc7cce2016-02-02 18:44:15 -0800862SkIRect SkCanvas::getTopLayerBounds() const {
863 SkBaseDevice* d = this->getTopDevice();
864 if (!d) {
865 return SkIRect::MakeEmpty();
866 }
867 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
868}
869
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000870SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000872 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000873 SkASSERT(rec && rec->fLayer);
874 return rec->fLayer->fDevice;
875}
876
Florin Malita0ed3b642017-01-13 16:56:38 +0000877SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000878 return fMCRec->fTopLayer->fDevice;
879}
880
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000881bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000882 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700883 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700884 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000885 return false;
886 }
887 weAllocated = true;
888 }
889
reedcf01e312015-05-23 19:14:51 -0700890 SkAutoPixmapUnlock unlocker;
891 if (bitmap->requestLock(&unlocker)) {
892 const SkPixmap& pm = unlocker.pixmap();
893 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
894 return true;
895 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000896 }
897
898 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500899 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000900 }
901 return false;
902}
reed@google.com51df9e32010-12-23 19:29:18 +0000903
bsalomon@google.comc6980972011-11-02 19:57:21 +0000904bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000905 SkIRect r = srcRect;
906 const SkISize size = this->getBaseLayerSize();
907 if (!r.intersect(0, 0, size.width(), size.height())) {
908 bitmap->reset();
909 return false;
910 }
911
reed84825042014-09-02 12:50:45 -0700912 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000913 // bitmap will already be reset.
914 return false;
915 }
916 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
917 bitmap->reset();
918 return false;
919 }
920 return true;
921}
922
reed96472de2014-12-10 09:53:42 -0800923bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000924 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000925 if (!device) {
926 return false;
927 }
mtkleinf0f14112014-12-12 08:46:25 -0800928
Matt Sarett03dd6d52017-01-23 12:15:09 -0500929 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000930}
931
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000932bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700933 SkAutoPixmapUnlock unlocker;
934 if (bitmap.requestLock(&unlocker)) {
935 const SkPixmap& pm = unlocker.pixmap();
936 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000937 }
938 return false;
939}
940
Matt Sarett03dd6d52017-01-23 12:15:09 -0500941bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000942 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000943 SkBaseDevice* device = this->getDevice();
944 if (!device) {
945 return false;
946 }
947
Matt Sarett03dd6d52017-01-23 12:15:09 -0500948 // This check gives us an early out and prevents generation ID churn on the surface.
949 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
950 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
951 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
952 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000953 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000954
Matt Sarett03dd6d52017-01-23 12:15:09 -0500955 // Tell our owning surface to bump its generation ID.
956 const bool completeOverwrite =
957 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700958 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700959
Matt Sarett03dd6d52017-01-23 12:15:09 -0500960 // This can still fail, most notably in the case of a invalid color type or alpha type
961 // conversion. We could pull those checks into this function and avoid the unnecessary
962 // generation ID bump. But then we would be performing those checks twice, since they
963 // are also necessary at the bitmap/pixmap entry points.
964 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000965}
reed@google.com51df9e32010-12-23 19:29:18 +0000966
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967//////////////////////////////////////////////////////////////////////////////
968
reed@android.com8a1c16f2008-12-17 15:59:43 +0000969void SkCanvas::updateDeviceCMCache() {
970 if (fDeviceCMDirty) {
971 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700972 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000974
halcanary96fcdcc2015-08-27 07:41:13 -0700975 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700976 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000978 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979 do {
reedde6c5312016-09-02 12:10:07 -0700980 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700981 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982 }
983 fDeviceCMDirty = false;
984 }
985}
986
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987///////////////////////////////////////////////////////////////////////////////
988
reed2ff1fce2014-12-11 07:07:37 -0800989void SkCanvas::checkForDeferredSave() {
990 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800991 this->doSave();
992 }
993}
994
reedf0090cb2014-11-26 08:55:51 -0800995int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800996#ifdef SK_DEBUG
997 int count = 0;
998 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
999 for (;;) {
1000 const MCRec* rec = (const MCRec*)iter.next();
1001 if (!rec) {
1002 break;
1003 }
1004 count += 1 + rec->fDeferredSaveCount;
1005 }
1006 SkASSERT(count == fSaveCount);
1007#endif
1008 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001009}
1010
1011int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001012 fSaveCount += 1;
1013 fMCRec->fDeferredSaveCount += 1;
1014 return this->getSaveCount() - 1; // return our prev value
1015}
1016
1017void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001018 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001019
1020 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1021 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001022 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001023}
1024
1025void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001026 if (fMCRec->fDeferredSaveCount > 0) {
1027 SkASSERT(fSaveCount > 1);
1028 fSaveCount -= 1;
1029 fMCRec->fDeferredSaveCount -= 1;
1030 } else {
1031 // check for underflow
1032 if (fMCStack.count() > 1) {
1033 this->willRestore();
1034 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001035 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001036 this->internalRestore();
1037 this->didRestore();
1038 }
reedf0090cb2014-11-26 08:55:51 -08001039 }
1040}
1041
1042void SkCanvas::restoreToCount(int count) {
1043 // sanity check
1044 if (count < 1) {
1045 count = 1;
1046 }
mtkleinf0f14112014-12-12 08:46:25 -08001047
reedf0090cb2014-11-26 08:55:51 -08001048 int n = this->getSaveCount() - count;
1049 for (int i = 0; i < n; ++i) {
1050 this->restore();
1051 }
1052}
1053
reed2ff1fce2014-12-11 07:07:37 -08001054void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001055 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001056 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001057 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001058
reed687fa1c2015-04-07 08:00:56 -07001059 fClipStack->save();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001060#ifdef SK_USE_DEVICE_CLIPPING
1061 FOR_EACH_TOP_DEVICE(device->save());
1062#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001063}
1064
reed4960eee2015-12-18 07:09:18 -08001065bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001066 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067}
1068
reed4960eee2015-12-18 07:09:18 -08001069bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001070 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -05001071 SkIRect clipBounds = this->getDeviceClipBounds();
1072 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001073 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001074 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001075
reed96e657d2015-03-10 17:30:07 -07001076 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1077
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001078 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001079 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001080 if (bounds && !imageFilter->canComputeFastBounds()) {
1081 bounds = nullptr;
1082 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001083 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001084 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001085 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001087
reed96e657d2015-03-10 17:30:07 -07001088 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089 r.roundOut(&ir);
1090 // early exit if the layer's bounds are clipped out
1091 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001092 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001093 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001094 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001095 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001096 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001097 }
1098 } else { // no user bounds, so just use the clip
1099 ir = clipBounds;
1100 }
reed180aec42015-03-11 10:39:04 -07001101 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001102
reed4960eee2015-12-18 07:09:18 -08001103 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001104 // Simplify the current clips since they will be applied properly during restore()
Mike Reedc1f77742016-12-09 09:00:50 -05001105 fClipStack->clipDevRect(ir, kReplace_SkClipOp);
reed180aec42015-03-11 10:39:04 -07001106 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001107 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001108 }
1109
1110 if (intersection) {
1111 *intersection = ir;
1112 }
1113 return true;
1114}
1115
reed4960eee2015-12-18 07:09:18 -08001116
reed4960eee2015-12-18 07:09:18 -08001117int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1118 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001119}
1120
reed70ee31b2015-12-10 13:44:45 -08001121int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001122 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1123}
1124
1125int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1126 SaveLayerRec rec(origRec);
1127 if (gIgnoreSaveLayerBounds) {
1128 rec.fBounds = nullptr;
1129 }
1130 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1131 fSaveCount += 1;
1132 this->internalSaveLayer(rec, strategy);
1133 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001134}
1135
reeda2217ef2016-07-20 06:04:34 -07001136void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001137 SkBaseDevice* dst, const SkIPoint& dstOrigin,
1138 const SkMatrix& ctm, const SkClipStack* clipStack) {
reeda2217ef2016-07-20 06:04:34 -07001139 SkDraw draw;
1140 SkRasterClip rc;
1141 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1142 if (!dst->accessPixels(&draw.fDst)) {
1143 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001144 }
reeda2217ef2016-07-20 06:04:34 -07001145 draw.fMatrix = &SkMatrix::I();
1146 draw.fRC = &rc;
1147 draw.fClipStack = clipStack;
1148 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001149
1150 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001151 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001152
Mike Reedc42a1cd2017-02-14 14:25:14 -05001153 int x = src->getOrigin().x() - dstOrigin.x();
1154 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001155 auto special = src->snapSpecial();
1156 if (special) {
1157 dst->drawSpecial(draw, special.get(), x, y, p);
1158 }
robertphillips7354a4b2015-12-16 05:08:27 -08001159}
reed70ee31b2015-12-10 13:44:45 -08001160
reed129ed1c2016-02-22 06:42:31 -08001161static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1162 const SkPaint* paint) {
1163 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1164 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001165 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001166 const bool hasImageFilter = paint && paint->getImageFilter();
1167
1168 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1169 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1170 // force to L32
1171 return SkImageInfo::MakeN32(w, h, alphaType);
1172 } else {
1173 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001174 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001175 }
1176}
1177
reed4960eee2015-12-18 07:09:18 -08001178void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1179 const SkRect* bounds = rec.fBounds;
1180 const SkPaint* paint = rec.fPaint;
1181 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1182
reed8c30a812016-04-20 16:36:51 -07001183 SkLazyPaint lazyP;
1184 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1185 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001186 SkMatrix remainder;
1187 SkSize scale;
1188 /*
1189 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1190 * but they do handle scaling. To accommodate this, we do the following:
1191 *
1192 * 1. Stash off the current CTM
1193 * 2. Decompose the CTM into SCALE and REMAINDER
1194 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1195 * contains the REMAINDER
1196 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1197 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1198 * of the original imagefilter, and draw that (via drawSprite)
1199 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1200 *
1201 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1202 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1203 */
reed96a04f32016-04-25 09:25:15 -07001204 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001205 stashedMatrix.decomposeScale(&scale, &remainder))
1206 {
1207 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1208 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1209 SkPaint* p = lazyP.set(*paint);
1210 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1211 SkFilterQuality::kLow_SkFilterQuality,
1212 sk_ref_sp(imageFilter)));
1213 imageFilter = p->getImageFilter();
1214 paint = p;
1215 }
reed8c30a812016-04-20 16:36:51 -07001216
junov@chromium.orga907ac32012-02-24 21:54:07 +00001217 // do this before we create the layer. We don't call the public save() since
1218 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001219 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001220
1221 fDeviceCMDirty = true;
1222
1223 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001224 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001225 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226 }
1227
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001228 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1229 // the clipRectBounds() call above?
1230 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001231 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001232 }
1233
reed4960eee2015-12-18 07:09:18 -08001234 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001235 SkPixelGeometry geo = fProps.pixelGeometry();
1236 if (paint) {
reed76033be2015-03-14 10:54:31 -07001237 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001238 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001239 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001240 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001241 }
1242 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001243
robertphillips5139e502016-07-19 05:10:40 -07001244 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001245 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001246 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001247 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001248 }
reedb2db8982014-11-13 12:41:02 -08001249
robertphillips5139e502016-07-19 05:10:40 -07001250 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001251 paint);
1252
Hal Canary704cd322016-11-07 14:13:52 -05001253 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001254 {
reed70ee31b2015-12-10 13:44:45 -08001255 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001256 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001257 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001258 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001259 preserveLCDText,
1260 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001261 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1262 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001263 return;
reed61f501f2015-04-29 08:34:00 -07001264 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001265 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001266#ifndef SK_USE_DEVICE_CLIPPING
1267 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1268#endif
robertphillips7354a4b2015-12-16 05:08:27 -08001269
Hal Canary704cd322016-11-07 14:13:52 -05001270 DeviceCM* layer =
1271 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272
Mike Reedb43a3e02017-02-11 10:18:58 -05001273 // only have a "next" if this new layer doesn't affect the clip (rare)
1274 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275 fMCRec->fLayer = layer;
1276 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001277
1278 if (rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001279 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
reeda2217ef2016-07-20 06:04:34 -07001280 fMCRec->fMatrix, this->getClipStack());
1281 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001282
1283#ifdef SK_USE_DEVICE_CLIPPING
1284 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1285
1286 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1287 if (layer->fNext) {
1288 // need to punch a hole in the previous device, so we don't draw there, given that
1289 // the new top-layer will allow drawing to happen "below" it.
1290 SkRegion hole(ir);
1291 do {
1292 layer = layer->fNext;
1293 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1294 } while (layer->fNext);
1295 }
1296#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297}
1298
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001299int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001300 if (0xFF == alpha) {
1301 return this->saveLayer(bounds, nullptr);
1302 } else {
1303 SkPaint tmpPaint;
1304 tmpPaint.setAlpha(alpha);
1305 return this->saveLayer(bounds, &tmpPaint);
1306 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001307}
1308
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309void SkCanvas::internalRestore() {
1310 SkASSERT(fMCStack.count() != 0);
1311
1312 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313
reed687fa1c2015-04-07 08:00:56 -07001314 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001315
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001316 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317 DeviceCM* layer = fMCRec->fLayer; // may be null
1318 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001319 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320
1321 // now do the normal restore()
1322 fMCRec->~MCRec(); // balanced in save()
1323 fMCStack.pop_back();
1324 fMCRec = (MCRec*)fMCStack.back();
1325
Mike Reedc42a1cd2017-02-14 14:25:14 -05001326#ifdef SK_USE_DEVICE_CLIPPING
1327 if (fMCRec) {
1328 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1329 }
1330#endif
1331
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1333 since if we're being recorded, we don't want to record this (the
1334 recorder will have already recorded the restore).
1335 */
bsalomon49f085d2014-09-05 13:34:00 -07001336 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001337 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001338 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001339 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001340 // restore what we smashed in internalSaveLayer
1341 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001342 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001344 delete layer;
reedb679ca82015-04-07 04:40:48 -07001345 } else {
1346 // we're at the root
reeda499f902015-05-01 09:34:31 -07001347 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001348 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001349 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001351 }
msarettfbfa2582016-08-12 08:29:08 -07001352
1353 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001354 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001355 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1356 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001357}
1358
reede8f30622016-03-23 18:59:25 -07001359sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001360 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001361 props = &fProps;
1362 }
1363 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001364}
1365
reede8f30622016-03-23 18:59:25 -07001366sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001367 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001368 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001369}
1370
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001371SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001372 return this->onImageInfo();
1373}
1374
1375SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001376 SkBaseDevice* dev = this->getDevice();
1377 if (dev) {
1378 return dev->imageInfo();
1379 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001380 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001381 }
1382}
1383
brianosman898235c2016-04-06 07:38:23 -07001384bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001385 return this->onGetProps(props);
1386}
1387
1388bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001389 SkBaseDevice* dev = this->getDevice();
1390 if (dev) {
1391 if (props) {
1392 *props = fProps;
1393 }
1394 return true;
1395 } else {
1396 return false;
1397 }
1398}
1399
reed6ceeebd2016-03-09 14:26:26 -08001400bool SkCanvas::peekPixels(SkPixmap* pmap) {
1401 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001402}
1403
reed884e97c2015-05-26 11:31:54 -07001404bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001405 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001406 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001407}
1408
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001409void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001410 SkPixmap pmap;
1411 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001412 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001413 }
1414 if (info) {
1415 *info = pmap.info();
1416 }
1417 if (rowBytes) {
1418 *rowBytes = pmap.rowBytes();
1419 }
1420 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001421 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001422 }
reed884e97c2015-05-26 11:31:54 -07001423 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001424}
1425
reed884e97c2015-05-26 11:31:54 -07001426bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001427 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001428 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001429}
1430
reed@android.com8a1c16f2008-12-17 15:59:43 +00001431/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001432
reed7503d602016-07-15 14:23:29 -07001433void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001434 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001435 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436 paint = &tmp;
1437 }
reed@google.com4b226022011-01-11 18:32:13 +00001438
reed@google.com8926b162012-03-23 15:36:36 +00001439 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001440
reed@android.com8a1c16f2008-12-17 15:59:43 +00001441 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001442 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001443 paint = &looper.paint();
1444 SkImageFilter* filter = paint->getImageFilter();
1445 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001446 if (filter) {
1447 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1448 if (specialImage) {
1449 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1450 }
reed@google.com76dd2772012-01-05 21:15:07 +00001451 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001452 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001453 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001454 }
reeda2217ef2016-07-20 06:04:34 -07001455
reed@google.com4e2b3d32011-04-07 14:18:59 +00001456 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001457}
1458
reed32704672015-12-16 08:27:10 -08001459/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001460
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001461void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001462 if (dx || dy) {
1463 this->checkForDeferredSave();
1464 fDeviceCMDirty = true;
1465 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001466
reedfe69b502016-09-12 06:31:48 -07001467 // Translate shouldn't affect the is-scale-translateness of the matrix.
1468 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001469
Mike Reedc42a1cd2017-02-14 14:25:14 -05001470#ifdef SK_USE_DEVICE_CLIPPING
1471 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1472#endif
1473
reedfe69b502016-09-12 06:31:48 -07001474 this->didTranslate(dx,dy);
1475 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476}
1477
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001478void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001479 SkMatrix m;
1480 m.setScale(sx, sy);
1481 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482}
1483
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001484void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001485 SkMatrix m;
1486 m.setRotate(degrees);
1487 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488}
1489
bungeman7438bfc2016-07-12 15:01:19 -07001490void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1491 SkMatrix m;
1492 m.setRotate(degrees, px, py);
1493 this->concat(m);
1494}
1495
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001496void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001497 SkMatrix m;
1498 m.setSkew(sx, sy);
1499 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001500}
1501
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001502void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001503 if (matrix.isIdentity()) {
1504 return;
1505 }
1506
reed2ff1fce2014-12-11 07:07:37 -08001507 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001509 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001510 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001511
1512#ifdef SK_USE_DEVICE_CLIPPING
1513 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1514#endif
1515
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001516 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001517}
1518
reed8c30a812016-04-20 16:36:51 -07001519void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001520 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001521 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001522 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001523
1524#ifdef SK_USE_DEVICE_CLIPPING
1525 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1526#endif
reed8c30a812016-04-20 16:36:51 -07001527}
1528
1529void SkCanvas::setMatrix(const SkMatrix& matrix) {
1530 this->checkForDeferredSave();
1531 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001532 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001533}
1534
reed@android.com8a1c16f2008-12-17 15:59:43 +00001535void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001536 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001537}
1538
vjiaoblack95302da2016-07-21 10:25:54 -07001539#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001540void SkCanvas::translateZ(SkScalar z) {
1541 this->checkForDeferredSave();
1542 this->fMCRec->fCurDrawDepth += z;
1543 this->didTranslateZ(z);
1544}
1545
1546SkScalar SkCanvas::getZ() const {
1547 return this->fMCRec->fCurDrawDepth;
1548}
1549
vjiaoblack95302da2016-07-21 10:25:54 -07001550void SkCanvas::setLights(sk_sp<SkLights> lights) {
1551 this->fLights = lights;
1552}
1553
1554sk_sp<SkLights> SkCanvas::getLights() const {
1555 return this->fLights;
1556}
1557#endif
1558
reed@android.com8a1c16f2008-12-17 15:59:43 +00001559//////////////////////////////////////////////////////////////////////////////
1560
Mike Reedc1f77742016-12-09 09:00:50 -05001561void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001562 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001563 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1564 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001565}
1566
Mike Reedc1f77742016-12-09 09:00:50 -05001567void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001568 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001569
1570#ifdef SK_USE_DEVICE_CLIPPING
1571 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
1572#endif
1573
reedc64eff52015-11-21 12:39:45 -08001574 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001575 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1576 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1577 isAA);
reedc64eff52015-11-21 12:39:45 -08001578 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001579 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001580}
1581
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001582void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1583 fClipRestrictionRect = rect;
1584 fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
Mike Reedd519d482017-02-16 11:04:52 -05001585 if (fClipRestrictionRect.isEmpty()) {
1586 // we notify the device, but we *dont* resolve deferred saves (since we're just
1587 // removing the restriction if the rect is empty. how I hate this api.
1588#ifdef SK_USE_DEVICE_CLIPPING
1589 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
1590#endif
1591 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001592 this->checkForDeferredSave();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001593#ifdef SK_USE_DEVICE_CLIPPING
Mike Reedd519d482017-02-16 11:04:52 -05001594 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001595#endif
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001596 AutoValidateClip avc(this);
1597 fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
1598 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
1599 fDeviceCMDirty = true;
1600 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1601 }
1602}
1603
Mike Reedc1f77742016-12-09 09:00:50 -05001604void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001605 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001606 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001607 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001608 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1609 } else {
1610 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001611 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001612}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001613
Mike Reedc1f77742016-12-09 09:00:50 -05001614void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001615 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001616
Brian Salomona3b45d42016-10-03 11:36:16 -04001617 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001618
Brian Salomona3b45d42016-10-03 11:36:16 -04001619 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001620
1621#ifdef SK_USE_DEVICE_CLIPPING
1622 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
1623#endif
1624
Brian Salomona3b45d42016-10-03 11:36:16 -04001625 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1626 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1627 isAA);
1628 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1629 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001630}
1631
Mike Reedc1f77742016-12-09 09:00:50 -05001632void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001633 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001634 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001635
1636 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1637 SkRect r;
1638 if (path.isRect(&r)) {
1639 this->onClipRect(r, op, edgeStyle);
1640 return;
1641 }
1642 SkRRect rrect;
1643 if (path.isOval(&r)) {
1644 rrect.setOval(r);
1645 this->onClipRRect(rrect, op, edgeStyle);
1646 return;
1647 }
1648 if (path.isRRect(&rrect)) {
1649 this->onClipRRect(rrect, op, edgeStyle);
1650 return;
1651 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001652 }
robertphillips39f05382015-11-24 09:30:12 -08001653
1654 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001655}
1656
Mike Reedc1f77742016-12-09 09:00:50 -05001657void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001658 AutoValidateClip avc(this);
1659
reed@android.com8a1c16f2008-12-17 15:59:43 +00001660 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001661 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001662
1663#ifdef SK_USE_DEVICE_CLIPPING
1664 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
1665#endif
1666
Brian Salomona3b45d42016-10-03 11:36:16 -04001667 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001668
Brian Salomona3b45d42016-10-03 11:36:16 -04001669 const SkPath* rasterClipPath = &path;
1670 const SkMatrix* matrix = &fMCRec->fMatrix;
1671 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001672 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001673 isAA = getClipStack()->asPath(&tempPath);
1674 rasterClipPath = &tempPath;
1675 matrix = &SkMatrix::I();
Mike Reedc1f77742016-12-09 09:00:50 -05001676 op = kReplace_SkClipOp;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001677 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001678 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1679 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001680 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681}
1682
Mike Reedc1f77742016-12-09 09:00:50 -05001683void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001684 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001685 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001686}
1687
Mike Reedc1f77742016-12-09 09:00:50 -05001688void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001689#ifdef SK_USE_DEVICE_CLIPPING
1690 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
1691#endif
1692
reed@google.com5c3d1472011-02-22 19:12:23 +00001693 AutoValidateClip avc(this);
1694
reed@android.com8a1c16f2008-12-17 15:59:43 +00001695 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001696
reed@google.com5c3d1472011-02-22 19:12:23 +00001697 // todo: signal fClipStack that we have a region, and therefore (I guess)
1698 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001699 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001700
reed73603f32016-09-20 08:42:38 -07001701 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001702 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001703}
1704
reed@google.com819c9212011-02-23 18:56:55 +00001705#ifdef SK_DEBUG
1706void SkCanvas::validateClip() const {
1707 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001708 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001709 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001710 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001711 return;
1712 }
1713
reed@google.com819c9212011-02-23 18:56:55 +00001714 SkIRect ir;
1715 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001716 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001717
reed687fa1c2015-04-07 08:00:56 -07001718 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001719 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001720 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001721 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001722 case SkClipStack::Element::kRect_Type:
1723 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001724 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001725 break;
1726 case SkClipStack::Element::kEmpty_Type:
1727 tmpClip.setEmpty();
1728 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001729 default: {
1730 SkPath path;
1731 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001732 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1733 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001734 break;
1735 }
reed@google.com819c9212011-02-23 18:56:55 +00001736 }
1737 }
reed@google.com819c9212011-02-23 18:56:55 +00001738}
1739#endif
1740
reed@google.com90c07ea2012-04-13 13:50:27 +00001741void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001742 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001743 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001744
halcanary96fcdcc2015-08-27 07:41:13 -07001745 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001746 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001747 }
1748}
1749
reed@google.com5c3d1472011-02-22 19:12:23 +00001750///////////////////////////////////////////////////////////////////////////////
1751
reed@google.com754de5f2014-02-24 19:38:20 +00001752bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001753 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001754}
1755
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001756bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001757 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001758}
1759
msarettfbfa2582016-08-12 08:29:08 -07001760static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1761#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1762 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1763 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1764 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1765 return 0xF != _mm_movemask_ps(mask);
1766#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1767 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1768 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1769 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1770 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1771#else
1772 SkRect devRectAsRect;
1773 SkRect devClipAsRect;
1774 devRect.store(&devRectAsRect.fLeft);
1775 devClip.store(&devClipAsRect.fLeft);
1776 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1777#endif
1778}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001779
msarettfbfa2582016-08-12 08:29:08 -07001780// It's important for this function to not be inlined. Otherwise the compiler will share code
1781// between the fast path and the slow path, resulting in two slow paths.
1782static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1783 const SkMatrix& matrix) {
1784 SkRect deviceRect;
1785 matrix.mapRect(&deviceRect, src);
1786 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1787}
1788
1789bool SkCanvas::quickReject(const SkRect& src) const {
1790#ifdef SK_DEBUG
1791 // Verify that fDeviceClipBounds are set properly.
1792 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001793 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001794 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001795 } else {
msarettfbfa2582016-08-12 08:29:08 -07001796 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001797 }
msarettfbfa2582016-08-12 08:29:08 -07001798
msarett9637ea92016-08-18 14:03:30 -07001799 // Verify that fIsScaleTranslate is set properly.
1800 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001801#endif
1802
msarett9637ea92016-08-18 14:03:30 -07001803 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001804 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1805 }
1806
1807 // We inline the implementation of mapScaleTranslate() for the fast path.
1808 float sx = fMCRec->fMatrix.getScaleX();
1809 float sy = fMCRec->fMatrix.getScaleY();
1810 float tx = fMCRec->fMatrix.getTranslateX();
1811 float ty = fMCRec->fMatrix.getTranslateY();
1812 Sk4f scale(sx, sy, sx, sy);
1813 Sk4f trans(tx, ty, tx, ty);
1814
1815 // Apply matrix.
1816 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1817
1818 // Make sure left < right, top < bottom.
1819 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1820 Sk4f min = Sk4f::Min(ltrb, rblt);
1821 Sk4f max = Sk4f::Max(ltrb, rblt);
1822 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1823 // ARM this sequence generates the fastest (a single instruction).
1824 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1825
1826 // Check if the device rect is NaN or outside the clip.
1827 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001828}
1829
reed@google.com3b3e8952012-08-16 20:53:31 +00001830bool SkCanvas::quickReject(const SkPath& path) const {
1831 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001832}
1833
Mike Reed42e8c532017-01-23 14:09:13 -05001834SkRect SkCanvas::onGetLocalClipBounds() const {
1835 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001836 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001837 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001838 }
1839
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001840 SkMatrix inverse;
1841 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001842 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001843 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001844 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001845
Mike Reed42e8c532017-01-23 14:09:13 -05001846 SkRect bounds;
1847 SkRect r;
1848 // adjust it outwards in case we are antialiasing
1849 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001850
Mike Reed42e8c532017-01-23 14:09:13 -05001851 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1852 ibounds.fRight + inset, ibounds.fBottom + inset);
1853 inverse.mapRect(&bounds, r);
1854 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001855}
1856
Mike Reed42e8c532017-01-23 14:09:13 -05001857SkIRect SkCanvas::onGetDeviceClipBounds() const {
reed1f836ee2014-07-07 07:49:34 -07001858 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001859 if (clip.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001860 return SkIRect::MakeEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001861 }
Mike Reed42e8c532017-01-23 14:09:13 -05001862 return clip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001863}
1864
reed@android.com8a1c16f2008-12-17 15:59:43 +00001865const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001866 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001867}
1868
Mike Reed3726a4a2017-01-19 11:36:41 -05001869void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1870 // we know that ganesh doesn't track the rgn, so ask for its clipstack
1871 if (this->getGrContext()) {
1872 SkPath path;
1873 this->getClipStack()->asPath(&path);
1874 SkISize size = this->getBaseLayerSize();
1875 rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
1876 } else {
1877 *rgn = fMCRec->fRasterClip.forceGetBW();
1878 }
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001879}
1880
Brian Osman11052242016-10-27 14:47:55 -04001881GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001882 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001883 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001884}
1885
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001886GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001887 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001888 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001889}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001890
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001891void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1892 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001893 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001894 if (outer.isEmpty()) {
1895 return;
1896 }
1897 if (inner.isEmpty()) {
1898 this->drawRRect(outer, paint);
1899 return;
1900 }
1901
1902 // We don't have this method (yet), but technically this is what we should
1903 // be able to assert...
1904 // SkASSERT(outer.contains(inner));
1905 //
1906 // For now at least check for containment of bounds
1907 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1908
1909 this->onDrawDRRect(outer, inner, paint);
1910}
1911
reed41af9662015-01-05 07:49:08 -08001912// These need to stop being virtual -- clients need to override the onDraw... versions
1913
1914void SkCanvas::drawPaint(const SkPaint& paint) {
1915 this->onDrawPaint(paint);
1916}
1917
1918void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1919 this->onDrawRect(r, paint);
1920}
1921
msarettdca352e2016-08-26 06:37:45 -07001922void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1923 if (region.isEmpty()) {
1924 return;
1925 }
1926
1927 if (region.isRect()) {
1928 return this->drawIRect(region.getBounds(), paint);
1929 }
1930
1931 this->onDrawRegion(region, paint);
1932}
1933
reed41af9662015-01-05 07:49:08 -08001934void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1935 this->onDrawOval(r, paint);
1936}
1937
1938void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1939 this->onDrawRRect(rrect, paint);
1940}
1941
1942void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1943 this->onDrawPoints(mode, count, pts, paint);
1944}
1945
1946void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001947 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001948 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001949 this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices,
1950 indexCount, paint);
1951}
1952
1953void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint,
1954 uint32_t flags) {
1955 RETURN_ON_NULL(vertices);
1956 this->onDrawVerticesObject(std::move(vertices), mode, paint, flags);
reed41af9662015-01-05 07:49:08 -08001957}
1958
1959void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1960 this->onDrawPath(path, paint);
1961}
1962
reeda85d4d02015-05-06 12:56:48 -07001963void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001964 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001965 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001966}
1967
reede47829b2015-08-06 10:02:53 -07001968void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1969 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001970 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001971 if (dst.isEmpty() || src.isEmpty()) {
1972 return;
1973 }
1974 this->onDrawImageRect(image, &src, dst, paint, constraint);
1975}
reed41af9662015-01-05 07:49:08 -08001976
reed84984ef2015-07-17 07:09:43 -07001977void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1978 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001979 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001980 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001981}
1982
reede47829b2015-08-06 10:02:53 -07001983void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1984 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001985 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001986 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1987 constraint);
1988}
reede47829b2015-08-06 10:02:53 -07001989
reed4c21dc52015-06-25 12:32:03 -07001990void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1991 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001992 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001993 if (dst.isEmpty()) {
1994 return;
1995 }
msarett552bca92016-08-03 06:53:26 -07001996 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1997 this->onDrawImageNine(image, center, dst, paint);
1998 } else {
reede47829b2015-08-06 10:02:53 -07001999 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002000 }
reed4c21dc52015-06-25 12:32:03 -07002001}
2002
msarett16882062016-08-16 09:31:08 -07002003void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2004 const SkPaint* paint) {
2005 RETURN_ON_NULL(image);
2006 if (dst.isEmpty()) {
2007 return;
2008 }
msarett71df2d72016-09-30 12:41:42 -07002009
2010 SkIRect bounds;
2011 Lattice latticePlusBounds = lattice;
2012 if (!latticePlusBounds.fBounds) {
2013 bounds = SkIRect::MakeWH(image->width(), image->height());
2014 latticePlusBounds.fBounds = &bounds;
2015 }
2016
2017 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
2018 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07002019 } else {
2020 this->drawImageRect(image, dst, paint);
2021 }
2022}
2023
reed41af9662015-01-05 07:49:08 -08002024void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002025 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002026 return;
2027 }
reed41af9662015-01-05 07:49:08 -08002028 this->onDrawBitmap(bitmap, dx, dy, paint);
2029}
2030
reede47829b2015-08-06 10:02:53 -07002031void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002032 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002033 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002034 return;
2035 }
reede47829b2015-08-06 10:02:53 -07002036 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002037}
2038
reed84984ef2015-07-17 07:09:43 -07002039void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2040 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002041 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002042}
2043
reede47829b2015-08-06 10:02:53 -07002044void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2045 SrcRectConstraint constraint) {
2046 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2047 constraint);
2048}
reede47829b2015-08-06 10:02:53 -07002049
reed41af9662015-01-05 07:49:08 -08002050void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2051 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002052 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002053 return;
2054 }
msarett552bca92016-08-03 06:53:26 -07002055 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2056 this->onDrawBitmapNine(bitmap, center, dst, paint);
2057 } else {
reeda5517e22015-07-14 10:54:12 -07002058 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002059 }
reed41af9662015-01-05 07:49:08 -08002060}
2061
msarettc573a402016-08-02 08:05:56 -07002062void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2063 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002064 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002065 return;
2066 }
msarett71df2d72016-09-30 12:41:42 -07002067
2068 SkIRect bounds;
2069 Lattice latticePlusBounds = lattice;
2070 if (!latticePlusBounds.fBounds) {
2071 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2072 latticePlusBounds.fBounds = &bounds;
2073 }
2074
2075 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2076 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002077 } else {
msarett16882062016-08-16 09:31:08 -07002078 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002079 }
msarettc573a402016-08-02 08:05:56 -07002080}
2081
reed71c3c762015-06-24 10:29:17 -07002082void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002083 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002084 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002085 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002086 if (count <= 0) {
2087 return;
2088 }
Joe Gregorioc4859072017-01-20 14:21:27 +00002089 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002090 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002091 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002092}
2093
reedf70b5312016-03-04 16:36:20 -08002094void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2095 if (key) {
2096 this->onDrawAnnotation(rect, key, value);
2097 }
2098}
2099
reede47829b2015-08-06 10:02:53 -07002100void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2101 const SkPaint* paint, SrcRectConstraint constraint) {
2102 if (src) {
2103 this->drawImageRect(image, *src, dst, paint, constraint);
2104 } else {
2105 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2106 dst, paint, constraint);
2107 }
2108}
2109void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2110 const SkPaint* paint, SrcRectConstraint constraint) {
2111 if (src) {
2112 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2113 } else {
2114 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2115 dst, paint, constraint);
2116 }
2117}
2118
tomhudsoncb3bd182016-05-18 07:24:16 -07002119void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2120 SkIRect layer_bounds = this->getTopLayerBounds();
2121 if (matrix) {
2122 *matrix = this->getTotalMatrix();
2123 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2124 }
2125 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05002126 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07002127 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2128 }
2129}
2130
reed@android.com8a1c16f2008-12-17 15:59:43 +00002131//////////////////////////////////////////////////////////////////////////////
2132// These are the virtual drawing methods
2133//////////////////////////////////////////////////////////////////////////////
2134
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002135void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002136 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002137 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2138 }
2139}
2140
reed41af9662015-01-05 07:49:08 -08002141void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002142 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002143 this->internalDrawPaint(paint);
2144}
2145
2146void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002147 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002148
2149 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002150 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151 }
2152
reed@google.com4e2b3d32011-04-07 14:18:59 +00002153 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002154}
2155
reed41af9662015-01-05 07:49:08 -08002156void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2157 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002158 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002159 if ((long)count <= 0) {
2160 return;
2161 }
2162
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002163 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002164 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002165 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002166 // special-case 2 points (common for drawing a single line)
2167 if (2 == count) {
2168 r.set(pts[0], pts[1]);
2169 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002170 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002171 }
senorblanco87e066e2015-10-28 11:23:36 -07002172 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2173 return;
2174 }
2175 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002176 }
reed@google.coma584aed2012-05-16 14:06:02 +00002177
halcanary96fcdcc2015-08-27 07:41:13 -07002178 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002179
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002180 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002181
reed@android.com8a1c16f2008-12-17 15:59:43 +00002182 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002183 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002184 }
reed@google.com4b226022011-01-11 18:32:13 +00002185
reed@google.com4e2b3d32011-04-07 14:18:59 +00002186 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002187}
2188
reed4a167172016-08-18 17:15:25 -07002189static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2190 return ((intptr_t)paint.getImageFilter() |
2191#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2192 (intptr_t)canvas->getDrawFilter() |
2193#endif
2194 (intptr_t)paint.getLooper() ) != 0;
2195}
2196
reed41af9662015-01-05 07:49:08 -08002197void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002198 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002199 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002200 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002201 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002202 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2203 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2204 SkRect tmp(r);
2205 tmp.sort();
2206
senorblanco87e066e2015-10-28 11:23:36 -07002207 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2208 return;
2209 }
2210 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002211 }
reed@google.com4b226022011-01-11 18:32:13 +00002212
reed4a167172016-08-18 17:15:25 -07002213 if (needs_autodrawlooper(this, paint)) {
2214 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002215
reed4a167172016-08-18 17:15:25 -07002216 while (iter.next()) {
2217 iter.fDevice->drawRect(iter, r, looper.paint());
2218 }
2219
2220 LOOPER_END
2221 } else {
2222 this->predrawNotify(bounds, &paint, false);
2223 SkDrawIter iter(this);
2224 while (iter.next()) {
2225 iter.fDevice->drawRect(iter, r, paint);
2226 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002227 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002228}
2229
msarett44df6512016-08-25 13:54:30 -07002230void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2231 SkRect storage;
2232 SkRect regionRect = SkRect::Make(region.getBounds());
2233 const SkRect* bounds = nullptr;
2234 if (paint.canComputeFastBounds()) {
2235 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2236 return;
2237 }
2238 bounds = &regionRect;
2239 }
2240
2241 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2242
2243 while (iter.next()) {
2244 iter.fDevice->drawRegion(iter, region, looper.paint());
2245 }
2246
2247 LOOPER_END
2248}
2249
reed41af9662015-01-05 07:49:08 -08002250void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002251 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002252 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002253 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002254 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002255 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2256 return;
2257 }
2258 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002259 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002260
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002261 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002262
2263 while (iter.next()) {
2264 iter.fDevice->drawOval(iter, oval, looper.paint());
2265 }
2266
2267 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002268}
2269
bsalomonac3aa242016-08-19 11:25:19 -07002270void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2271 SkScalar sweepAngle, bool useCenter,
2272 const SkPaint& paint) {
2273 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2274 const SkRect* bounds = nullptr;
2275 if (paint.canComputeFastBounds()) {
2276 SkRect storage;
2277 // Note we're using the entire oval as the bounds.
2278 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2279 return;
2280 }
2281 bounds = &oval;
2282 }
2283
2284 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2285
2286 while (iter.next()) {
2287 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2288 }
2289
2290 LOOPER_END
2291}
2292
reed41af9662015-01-05 07:49:08 -08002293void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002294 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002295 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002296 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002297 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002298 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2299 return;
2300 }
2301 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002302 }
2303
2304 if (rrect.isRect()) {
2305 // call the non-virtual version
2306 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002307 return;
2308 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002309 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002310 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2311 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002312 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002313
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002314 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002315
2316 while (iter.next()) {
2317 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2318 }
2319
2320 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002321}
2322
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002323void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2324 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002325 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002326 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002327 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002328 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2329 return;
2330 }
2331 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002332 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002333
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002334 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002335
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002336 while (iter.next()) {
2337 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2338 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002339
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002340 LOOPER_END
2341}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002342
reed41af9662015-01-05 07:49:08 -08002343void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002344 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002345 if (!path.isFinite()) {
2346 return;
2347 }
2348
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002349 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002350 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002351 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002352 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002353 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2354 return;
2355 }
2356 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002357 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002358
2359 const SkRect& r = path.getBounds();
2360 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002361 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002362 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002363 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002364 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002365 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002366
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002367 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002368
2369 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002370 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002371 }
2372
reed@google.com4e2b3d32011-04-07 14:18:59 +00002373 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002374}
2375
reed262a71b2015-12-05 13:07:27 -08002376bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002377 if (!paint.getImageFilter()) {
2378 return false;
2379 }
2380
2381 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002382 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002383 return false;
2384 }
2385
2386 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2387 // Once we can filter and the filter will return a result larger than itself, we should be
2388 // able to remove this constraint.
2389 // skbug.com/4526
2390 //
2391 SkPoint pt;
2392 ctm.mapXY(x, y, &pt);
2393 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2394 return ir.contains(fMCRec->fRasterClip.getBounds());
2395}
2396
reeda85d4d02015-05-06 12:56:48 -07002397void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002398 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002399 SkRect bounds = SkRect::MakeXYWH(x, y,
2400 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002401 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002402 SkRect tmp = bounds;
2403 if (paint) {
2404 paint->computeFastBounds(tmp, &tmp);
2405 }
2406 if (this->quickReject(tmp)) {
2407 return;
2408 }
reeda85d4d02015-05-06 12:56:48 -07002409 }
halcanary9d524f22016-03-29 09:03:52 -07002410
reeda85d4d02015-05-06 12:56:48 -07002411 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002412 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002413 paint = lazy.init();
2414 }
reed262a71b2015-12-05 13:07:27 -08002415
reeda2217ef2016-07-20 06:04:34 -07002416 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002417 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2418 *paint);
2419 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002420 special = this->getDevice()->makeSpecial(image);
2421 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002422 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002423 }
2424 }
2425
reed262a71b2015-12-05 13:07:27 -08002426 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2427
reeda85d4d02015-05-06 12:56:48 -07002428 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002429 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002430 if (special) {
2431 SkPoint pt;
2432 iter.fMatrix->mapXY(x, y, &pt);
2433 iter.fDevice->drawSpecial(iter, special.get(),
2434 SkScalarRoundToInt(pt.fX),
2435 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002436 } else {
2437 iter.fDevice->drawImage(iter, image, x, y, pnt);
2438 }
reeda85d4d02015-05-06 12:56:48 -07002439 }
halcanary9d524f22016-03-29 09:03:52 -07002440
reeda85d4d02015-05-06 12:56:48 -07002441 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002442}
2443
reed41af9662015-01-05 07:49:08 -08002444void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002445 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002446 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002447 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002448 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002449 if (paint) {
2450 paint->computeFastBounds(dst, &storage);
2451 }
2452 if (this->quickReject(storage)) {
2453 return;
2454 }
reeda85d4d02015-05-06 12:56:48 -07002455 }
2456 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002457 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002458 paint = lazy.init();
2459 }
halcanary9d524f22016-03-29 09:03:52 -07002460
senorblancoc41e7e12015-12-07 12:51:30 -08002461 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002462 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002463
reeda85d4d02015-05-06 12:56:48 -07002464 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002465 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002466 }
halcanary9d524f22016-03-29 09:03:52 -07002467
reeda85d4d02015-05-06 12:56:48 -07002468 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002469}
2470
reed41af9662015-01-05 07:49:08 -08002471void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002472 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473 SkDEBUGCODE(bitmap.validate();)
2474
reed33366972015-10-08 09:22:02 -07002475 if (bitmap.drawsNothing()) {
2476 return;
2477 }
2478
2479 SkLazyPaint lazy;
2480 if (nullptr == paint) {
2481 paint = lazy.init();
2482 }
2483
2484 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2485
2486 SkRect storage;
2487 const SkRect* bounds = nullptr;
2488 if (paint->canComputeFastBounds()) {
2489 bitmap.getBounds(&storage);
2490 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002491 SkRect tmp = storage;
2492 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2493 return;
2494 }
2495 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496 }
reed@google.com4b226022011-01-11 18:32:13 +00002497
reeda2217ef2016-07-20 06:04:34 -07002498 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002499 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2500 *paint);
2501 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002502 special = this->getDevice()->makeSpecial(bitmap);
2503 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002504 drawAsSprite = false;
2505 }
2506 }
2507
reed262a71b2015-12-05 13:07:27 -08002508 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002509
2510 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002511 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002512 if (special) {
reed262a71b2015-12-05 13:07:27 -08002513 SkPoint pt;
2514 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002515 iter.fDevice->drawSpecial(iter, special.get(),
2516 SkScalarRoundToInt(pt.fX),
2517 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002518 } else {
2519 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2520 }
reed33366972015-10-08 09:22:02 -07002521 }
msarettfbfa2582016-08-12 08:29:08 -07002522
reed33366972015-10-08 09:22:02 -07002523 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002524}
2525
reed@google.com9987ec32011-09-07 11:57:52 +00002526// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002527void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002528 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002529 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002530 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002531 return;
2532 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002533
halcanary96fcdcc2015-08-27 07:41:13 -07002534 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002535 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002536 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2537 return;
2538 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002539 }
reed@google.com3d608122011-11-21 15:16:16 +00002540
reed@google.com33535f32012-09-25 15:37:50 +00002541 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002542 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002543 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002544 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002545
senorblancoc41e7e12015-12-07 12:51:30 -08002546 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002547 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002548
reed@google.com33535f32012-09-25 15:37:50 +00002549 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002550 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002551 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002552
reed@google.com33535f32012-09-25 15:37:50 +00002553 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002554}
2555
reed41af9662015-01-05 07:49:08 -08002556void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002557 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002558 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002559 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002560 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002561}
2562
reed4c21dc52015-06-25 12:32:03 -07002563void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2564 const SkPaint* paint) {
2565 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002566
halcanary96fcdcc2015-08-27 07:41:13 -07002567 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002568 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002569 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2570 return;
2571 }
reed@google.com3d608122011-11-21 15:16:16 +00002572 }
halcanary9d524f22016-03-29 09:03:52 -07002573
reed4c21dc52015-06-25 12:32:03 -07002574 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002575 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002576 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002577 }
halcanary9d524f22016-03-29 09:03:52 -07002578
senorblancoc41e7e12015-12-07 12:51:30 -08002579 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002580
reed4c21dc52015-06-25 12:32:03 -07002581 while (iter.next()) {
2582 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002583 }
halcanary9d524f22016-03-29 09:03:52 -07002584
reed4c21dc52015-06-25 12:32:03 -07002585 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002586}
2587
reed41af9662015-01-05 07:49:08 -08002588void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2589 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002590 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002591 SkDEBUGCODE(bitmap.validate();)
2592
halcanary96fcdcc2015-08-27 07:41:13 -07002593 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002594 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002595 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2596 return;
2597 }
reed4c21dc52015-06-25 12:32:03 -07002598 }
halcanary9d524f22016-03-29 09:03:52 -07002599
reed4c21dc52015-06-25 12:32:03 -07002600 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002601 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002602 paint = lazy.init();
2603 }
halcanary9d524f22016-03-29 09:03:52 -07002604
senorblancoc41e7e12015-12-07 12:51:30 -08002605 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002606
reed4c21dc52015-06-25 12:32:03 -07002607 while (iter.next()) {
2608 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2609 }
halcanary9d524f22016-03-29 09:03:52 -07002610
reed4c21dc52015-06-25 12:32:03 -07002611 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002612}
2613
msarett16882062016-08-16 09:31:08 -07002614void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2615 const SkPaint* paint) {
2616 if (nullptr == paint || paint->canComputeFastBounds()) {
2617 SkRect storage;
2618 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2619 return;
2620 }
2621 }
2622
2623 SkLazyPaint lazy;
2624 if (nullptr == paint) {
2625 paint = lazy.init();
2626 }
2627
2628 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2629
2630 while (iter.next()) {
2631 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2632 }
2633
2634 LOOPER_END
2635}
2636
2637void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2638 const SkRect& dst, const SkPaint* paint) {
2639 if (nullptr == paint || paint->canComputeFastBounds()) {
2640 SkRect storage;
2641 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2642 return;
2643 }
2644 }
2645
2646 SkLazyPaint lazy;
2647 if (nullptr == paint) {
2648 paint = lazy.init();
2649 }
2650
2651 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2652
2653 while (iter.next()) {
2654 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2655 }
2656
2657 LOOPER_END
2658}
2659
reed@google.comf67e4cf2011-03-15 20:56:58 +00002660class SkDeviceFilteredPaint {
2661public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002662 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002663 uint32_t filteredFlags = device->filterTextFlags(paint);
2664 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002665 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002666 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002667 fPaint = newPaint;
2668 } else {
2669 fPaint = &paint;
2670 }
2671 }
2672
reed@google.comf67e4cf2011-03-15 20:56:58 +00002673 const SkPaint& paint() const { return *fPaint; }
2674
2675private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002676 const SkPaint* fPaint;
2677 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002678};
2679
reed@google.come0d9ce82014-04-23 04:00:17 +00002680void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2681 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002682 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002683
2684 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002685 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002686 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002687 }
2688
reed@google.com4e2b3d32011-04-07 14:18:59 +00002689 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002690}
2691
reed@google.come0d9ce82014-04-23 04:00:17 +00002692void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2693 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002694 SkPoint textOffset = SkPoint::Make(0, 0);
2695
halcanary96fcdcc2015-08-27 07:41:13 -07002696 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002697
reed@android.com8a1c16f2008-12-17 15:59:43 +00002698 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002699 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002700 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002701 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002702 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002703
reed@google.com4e2b3d32011-04-07 14:18:59 +00002704 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002705}
2706
reed@google.come0d9ce82014-04-23 04:00:17 +00002707void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2708 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002709
2710 SkPoint textOffset = SkPoint::Make(0, constY);
2711
halcanary96fcdcc2015-08-27 07:41:13 -07002712 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002713
reed@android.com8a1c16f2008-12-17 15:59:43 +00002714 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002715 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002716 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002717 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002718 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002719
reed@google.com4e2b3d32011-04-07 14:18:59 +00002720 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002721}
2722
reed@google.come0d9ce82014-04-23 04:00:17 +00002723void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2724 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002725 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002726
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 while (iter.next()) {
2728 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002729 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002731
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002732 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002733}
2734
reed45561a02016-07-07 12:47:17 -07002735void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2736 const SkRect* cullRect, const SkPaint& paint) {
2737 if (cullRect && this->quickReject(*cullRect)) {
2738 return;
2739 }
2740
2741 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2742
2743 while (iter.next()) {
2744 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2745 }
2746
2747 LOOPER_END
2748}
2749
fmalita00d5c2c2014-08-21 08:53:26 -07002750void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2751 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002752
fmalita85d5eb92015-03-04 11:20:12 -08002753 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002754 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002755 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002756 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002757 SkRect tmp;
2758 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2759 return;
2760 }
2761 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002762 }
2763
fmalita024f9962015-03-03 19:08:17 -08002764 // We cannot filter in the looper as we normally do, because the paint is
2765 // incomplete at this point (text-related attributes are embedded within blob run paints).
2766 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002767 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002768
fmalita85d5eb92015-03-04 11:20:12 -08002769 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002770
fmalitaaa1b9122014-08-28 14:32:24 -07002771 while (iter.next()) {
2772 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002773 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002774 }
2775
fmalitaaa1b9122014-08-28 14:32:24 -07002776 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002777
2778 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002779}
2780
reed@google.come0d9ce82014-04-23 04:00:17 +00002781// These will become non-virtual, so they always call the (virtual) onDraw... method
2782void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2783 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002784 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002785 if (byteLength) {
2786 this->onDrawText(text, byteLength, x, y, paint);
2787 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002788}
2789void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2790 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002791 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002792 if (byteLength) {
2793 this->onDrawPosText(text, byteLength, pos, paint);
2794 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002795}
2796void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2797 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002798 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002799 if (byteLength) {
2800 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2801 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002802}
2803void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2804 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002805 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002806 if (byteLength) {
2807 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2808 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002809}
reed45561a02016-07-07 12:47:17 -07002810void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2811 const SkRect* cullRect, const SkPaint& paint) {
2812 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2813 if (byteLength) {
2814 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2815 }
2816}
fmalita00d5c2c2014-08-21 08:53:26 -07002817void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2818 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002819 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002820 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002821 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002822}
reed@google.come0d9ce82014-04-23 04:00:17 +00002823
reed41af9662015-01-05 07:49:08 -08002824void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2825 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002826 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002827 const uint16_t indices[], int indexCount,
2828 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002829 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002830 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002831
reed@android.com8a1c16f2008-12-17 15:59:43 +00002832 while (iter.next()) {
2833 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002834 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002835 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002836 }
reed@google.com4b226022011-01-11 18:32:13 +00002837
reed@google.com4e2b3d32011-04-07 14:18:59 +00002838 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002839}
2840
Brian Salomon199fb872017-02-06 09:41:10 -05002841void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode,
2842 const SkPaint& paint, uint32_t flags) {
2843 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2844 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2845
2846 while (iter.next()) {
2847 // In the common case of one iteration we could std::move vertices here.
2848 iter.fDevice->drawVerticesObject(iter, vertices, bmode, looper.paint(), flags);
2849 }
2850
2851 LOOPER_END
2852}
2853
2854void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode,
2855 const SkPaint& paint, uint32_t flags) {
2856 const SkPoint* texs =
2857 (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords();
2858 const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors();
2859 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs,
2860 colors, mode, vertices->indices(), vertices->indexCount(), paint);
2861}
2862
dandovb3c9d1c2014-08-12 08:34:29 -07002863void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002864 const SkPoint texCoords[4], SkBlendMode bmode,
2865 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002866 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002867 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002868 return;
2869 }
mtklein6cfa73a2014-08-13 13:33:49 -07002870
Mike Reedfaba3712016-11-03 14:45:31 -04002871 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002872}
2873
2874void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002875 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002876 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002877 // Since a patch is always within the convex hull of the control points, we discard it when its
2878 // bounding rectangle is completely outside the current clip.
2879 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002880 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002881 if (this->quickReject(bounds)) {
2882 return;
2883 }
mtklein6cfa73a2014-08-13 13:33:49 -07002884
halcanary96fcdcc2015-08-27 07:41:13 -07002885 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002886
dandovecfff212014-08-04 10:02:00 -07002887 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002888 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002889 }
mtklein6cfa73a2014-08-13 13:33:49 -07002890
dandovecfff212014-08-04 10:02:00 -07002891 LOOPER_END
2892}
2893
reeda8db7282015-07-07 10:22:31 -07002894void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002895 RETURN_ON_NULL(dr);
2896 if (x || y) {
2897 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2898 this->onDrawDrawable(dr, &matrix);
2899 } else {
2900 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002901 }
2902}
2903
reeda8db7282015-07-07 10:22:31 -07002904void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002905 RETURN_ON_NULL(dr);
2906 if (matrix && matrix->isIdentity()) {
2907 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002908 }
reede3b38ce2016-01-08 09:18:44 -08002909 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002910}
2911
2912void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002913 // drawable bounds are no longer reliable (e.g. android displaylist)
2914 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002915 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002916}
2917
reed71c3c762015-06-24 10:29:17 -07002918void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002919 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002920 const SkRect* cull, const SkPaint* paint) {
2921 if (cull && this->quickReject(*cull)) {
2922 return;
2923 }
2924
2925 SkPaint pnt;
2926 if (paint) {
2927 pnt = *paint;
2928 }
halcanary9d524f22016-03-29 09:03:52 -07002929
halcanary96fcdcc2015-08-27 07:41:13 -07002930 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002931 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002932 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002933 }
2934 LOOPER_END
2935}
2936
reedf70b5312016-03-04 16:36:20 -08002937void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2938 SkASSERT(key);
2939
2940 SkPaint paint;
2941 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2942 while (iter.next()) {
2943 iter.fDevice->drawAnnotation(iter, rect, key, value);
2944 }
2945 LOOPER_END
2946}
2947
reed@android.com8a1c16f2008-12-17 15:59:43 +00002948//////////////////////////////////////////////////////////////////////////////
2949// These methods are NOT virtual, and therefore must call back into virtual
2950// methods, rather than actually drawing themselves.
2951//////////////////////////////////////////////////////////////////////////////
2952
reed374772b2016-10-05 17:33:02 -07002953void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002954 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002955 SkPaint paint;
2956
2957 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002958 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002959 this->drawPaint(paint);
2960}
2961
reed374772b2016-10-05 17:33:02 -07002962void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002963 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002964 SkPaint paint;
2965
2966 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002967 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002968 this->drawPaint(paint);
2969}
2970
2971void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002972 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002973 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002974
reed@android.com8a1c16f2008-12-17 15:59:43 +00002975 pt.set(x, y);
2976 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2977}
2978
2979void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002980 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002981 SkPoint pt;
2982 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002983
reed@android.com8a1c16f2008-12-17 15:59:43 +00002984 pt.set(x, y);
2985 paint.setColor(color);
2986 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2987}
2988
2989void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2990 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002991 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002992 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002993
reed@android.com8a1c16f2008-12-17 15:59:43 +00002994 pts[0].set(x0, y0);
2995 pts[1].set(x1, y1);
2996 this->drawPoints(kLines_PointMode, 2, pts, paint);
2997}
2998
2999void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3000 SkScalar right, SkScalar bottom,
3001 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003002 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003003 SkRect r;
3004
3005 r.set(left, top, right, bottom);
3006 this->drawRect(r, paint);
3007}
3008
3009void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3010 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003011 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003012 if (radius < 0) {
3013 radius = 0;
3014 }
3015
3016 SkRect r;
3017 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003018 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003019}
3020
3021void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3022 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003023 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003024 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003025 SkRRect rrect;
3026 rrect.setRectXY(r, rx, ry);
3027 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003028 } else {
3029 this->drawRect(r, paint);
3030 }
3031}
3032
reed@android.com8a1c16f2008-12-17 15:59:43 +00003033void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3034 SkScalar sweepAngle, bool useCenter,
3035 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003036 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003037 if (oval.isEmpty() || !sweepAngle) {
3038 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003039 }
bsalomon21af9ca2016-08-25 12:29:23 -07003040 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003041}
3042
3043void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3044 const SkPath& path, SkScalar hOffset,
3045 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003046 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003047 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003048
reed@android.com8a1c16f2008-12-17 15:59:43 +00003049 matrix.setTranslate(hOffset, vOffset);
3050 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3051}
3052
reed@android.comf76bacf2009-05-13 14:00:33 +00003053///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003054
3055/**
3056 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3057 * against the playback cost of recursing into the subpicture to get at its actual ops.
3058 *
3059 * For now we pick a conservatively small value, though measurement (and other heuristics like
3060 * the type of ops contained) may justify changing this value.
3061 */
3062#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003063
reedd5fa1a42014-08-09 11:08:05 -07003064void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003065 RETURN_ON_NULL(picture);
3066
reed1c2c4412015-04-30 13:09:24 -07003067 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003068 if (matrix && matrix->isIdentity()) {
3069 matrix = nullptr;
3070 }
3071 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3072 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3073 picture->playback(this);
3074 } else {
3075 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003076 }
3077}
robertphillips9b14f262014-06-04 05:40:44 -07003078
reedd5fa1a42014-08-09 11:08:05 -07003079void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3080 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003081 if (!paint || paint->canComputeFastBounds()) {
3082 SkRect bounds = picture->cullRect();
3083 if (paint) {
3084 paint->computeFastBounds(bounds, &bounds);
3085 }
3086 if (matrix) {
3087 matrix->mapRect(&bounds);
3088 }
3089 if (this->quickReject(bounds)) {
3090 return;
3091 }
3092 }
3093
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003094 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003095 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003096}
3097
vjiaoblack95302da2016-07-21 10:25:54 -07003098#ifdef SK_EXPERIMENTAL_SHADOWING
3099void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3100 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003101 const SkPaint* paint,
3102 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003103 RETURN_ON_NULL(picture);
3104
3105 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3106
vjiaoblacke6f5d562016-08-25 06:30:23 -07003107 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003108}
3109
3110void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3111 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003112 const SkPaint* paint,
3113 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003114 if (!paint || paint->canComputeFastBounds()) {
3115 SkRect bounds = picture->cullRect();
3116 if (paint) {
3117 paint->computeFastBounds(bounds, &bounds);
3118 }
3119 if (matrix) {
3120 matrix->mapRect(&bounds);
3121 }
3122 if (this->quickReject(bounds)) {
3123 return;
3124 }
3125 }
3126
3127 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3128
vjiaoblacke6f5d562016-08-25 06:30:23 -07003129 sk_sp<SkImage> povDepthMap;
3130 sk_sp<SkImage> diffuseMap;
3131
vjiaoblack904527d2016-08-09 09:32:09 -07003132 // povDepthMap
3133 {
3134 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003135 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3136 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003137 sk_sp<SkLights> povLight = builder.finish();
3138
3139 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3140 picture->cullRect().height(),
3141 kBGRA_8888_SkColorType,
3142 kOpaque_SkAlphaType);
3143
3144 // Create a new surface (that matches the backend of canvas)
3145 // to create the povDepthMap
3146 sk_sp<SkSurface> surf(this->makeSurface(info));
3147
3148 // Wrap another SPFCanvas around the surface
3149 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3150 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3151
3152 // set the depth map canvas to have the light as the user's POV
3153 depthMapCanvas->setLights(std::move(povLight));
3154
3155 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003156 povDepthMap = surf->makeImageSnapshot();
3157 }
3158
3159 // diffuseMap
3160 {
3161 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3162 picture->cullRect().height(),
3163 kBGRA_8888_SkColorType,
3164 kOpaque_SkAlphaType);
3165
3166 sk_sp<SkSurface> surf(this->makeSurface(info));
3167 surf->getCanvas()->drawPicture(picture);
3168
3169 diffuseMap = surf->makeImageSnapshot();
3170 }
vjiaoblack904527d2016-08-09 09:32:09 -07003171
3172 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3173 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003174 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3175 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003176
3177 // TODO: pass the depth to the shader in vertices, or uniforms
3178 // so we don't have to render depth and color separately
3179 for (int i = 0; i < fLights->numLights(); ++i) {
3180 // skip over ambient lights; they don't cast shadows
3181 // lights that have shadow maps do not need updating (because lights are immutable)
3182 sk_sp<SkImage> depthMap;
3183 SkISize shMapSize;
3184
3185 if (fLights->light(i).getShadowMap() != nullptr) {
3186 continue;
3187 }
3188
3189 if (fLights->light(i).isRadial()) {
3190 shMapSize.fHeight = 1;
3191 shMapSize.fWidth = (int) picture->cullRect().width();
3192
3193 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3194 kBGRA_8888_SkColorType,
3195 kOpaque_SkAlphaType);
3196
3197 // Create new surface (that matches the backend of canvas)
3198 // for each shadow map
3199 sk_sp<SkSurface> surf(this->makeSurface(info));
3200
3201 // Wrap another SPFCanvas around the surface
3202 SkCanvas* depthMapCanvas = surf->getCanvas();
3203
3204 SkLights::Builder builder;
3205 builder.add(fLights->light(i));
3206 sk_sp<SkLights> curLight = builder.finish();
3207
3208 sk_sp<SkShader> shadowMapShader;
3209 shadowMapShader = SkRadialShadowMapShader::Make(
3210 povDepthShader, curLight,
3211 (int) picture->cullRect().width(),
3212 (int) picture->cullRect().height());
3213
3214 SkPaint shadowMapPaint;
3215 shadowMapPaint.setShader(std::move(shadowMapShader));
3216
3217 depthMapCanvas->setLights(curLight);
3218
3219 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3220 diffuseMap->height()),
3221 shadowMapPaint);
3222
3223 depthMap = surf->makeImageSnapshot();
3224
3225 } else {
3226 // TODO: compute the correct size of the depth map from the light properties
3227 // TODO: maybe add a kDepth_8_SkColorType
3228 // TODO: find actual max depth of picture
3229 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3230 fLights->light(i), 255,
3231 (int) picture->cullRect().width(),
3232 (int) picture->cullRect().height());
3233
3234 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3235 kBGRA_8888_SkColorType,
3236 kOpaque_SkAlphaType);
3237
3238 // Create a new surface (that matches the backend of canvas)
3239 // for each shadow map
3240 sk_sp<SkSurface> surf(this->makeSurface(info));
3241
3242 // Wrap another SPFCanvas around the surface
3243 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3244 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3245 depthMapCanvas->setShadowParams(params);
3246
3247 // set the depth map canvas to have the light we're drawing.
3248 SkLights::Builder builder;
3249 builder.add(fLights->light(i));
3250 sk_sp<SkLights> curLight = builder.finish();
3251 depthMapCanvas->setLights(std::move(curLight));
3252
3253 depthMapCanvas->drawPicture(picture);
3254 depthMap = surf->makeImageSnapshot();
3255 }
3256
3257 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3258 fLights->light(i).setShadowMap(std::move(depthMap));
3259 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3260 // we blur the variance map
3261 SkPaint blurPaint;
3262 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3263 params.fShadowRadius, nullptr));
3264
3265 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3266 kBGRA_8888_SkColorType,
3267 kOpaque_SkAlphaType);
3268
3269 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3270
3271 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3272
3273 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3274 }
3275 }
3276
3277 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003278 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3279 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003280 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003281 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003282 diffuseMap->height(),
3283 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003284
3285 shadowPaint.setShader(shadowShader);
3286
3287 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003288}
3289#endif
3290
reed@android.com8a1c16f2008-12-17 15:59:43 +00003291///////////////////////////////////////////////////////////////////////////////
3292///////////////////////////////////////////////////////////////////////////////
3293
reed3aafe112016-08-18 12:45:34 -07003294SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003295 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003296
3297 SkASSERT(canvas);
3298
reed3aafe112016-08-18 12:45:34 -07003299 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003300 fDone = !fImpl->next();
3301}
3302
3303SkCanvas::LayerIter::~LayerIter() {
3304 fImpl->~SkDrawIter();
3305}
3306
3307void SkCanvas::LayerIter::next() {
3308 fDone = !fImpl->next();
3309}
3310
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003311SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003312 return fImpl->getDevice();
3313}
3314
3315const SkMatrix& SkCanvas::LayerIter::matrix() const {
3316 return fImpl->getMatrix();
3317}
3318
3319const SkPaint& SkCanvas::LayerIter::paint() const {
3320 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003321 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003322 paint = &fDefaultPaint;
3323 }
3324 return *paint;
3325}
3326
reed1e7f5e72016-04-27 07:49:17 -07003327const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003328int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3329int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003330
3331///////////////////////////////////////////////////////////////////////////////
3332
fmalitac3b589a2014-06-05 12:40:07 -07003333SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003334
3335///////////////////////////////////////////////////////////////////////////////
3336
3337static bool supported_for_raster_canvas(const SkImageInfo& info) {
3338 switch (info.alphaType()) {
3339 case kPremul_SkAlphaType:
3340 case kOpaque_SkAlphaType:
3341 break;
3342 default:
3343 return false;
3344 }
3345
3346 switch (info.colorType()) {
3347 case kAlpha_8_SkColorType:
3348 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003349 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003350 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003351 break;
3352 default:
3353 return false;
3354 }
3355
3356 return true;
3357}
3358
Mike Reed5df49342016-11-12 08:06:55 -06003359std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3360 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003361 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003362 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003363 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003364
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003365 SkBitmap bitmap;
3366 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003367 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003368 }
Mike Reed5df49342016-11-12 08:06:55 -06003369 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003370}
reedd5fa1a42014-08-09 11:08:05 -07003371
3372///////////////////////////////////////////////////////////////////////////////
3373
3374SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003375 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003376 : fCanvas(canvas)
3377 , fSaveCount(canvas->getSaveCount())
3378{
bsalomon49f085d2014-09-05 13:34:00 -07003379 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003380 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003381 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003382 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003383 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003384 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003385 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003386 canvas->save();
3387 }
mtklein6cfa73a2014-08-13 13:33:49 -07003388
bsalomon49f085d2014-09-05 13:34:00 -07003389 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003390 canvas->concat(*matrix);
3391 }
3392}
3393
3394SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3395 fCanvas->restoreToCount(fSaveCount);
3396}
reede8f30622016-03-23 18:59:25 -07003397
Florin Malitaee424ac2016-12-01 12:47:59 -05003398///////////////////////////////////////////////////////////////////////////////
3399
3400SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3401 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3402
Florin Malita439ace92016-12-02 12:05:41 -05003403SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3404 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3405
Florin Malitaee424ac2016-12-01 12:47:59 -05003406SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3407 (void)this->INHERITED::getSaveLayerStrategy(rec);
3408 return kNoLayer_SaveLayerStrategy;
3409}
3410
3411///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003412
reed73603f32016-09-20 08:42:38 -07003413static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3414static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3415static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3416static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3417static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3418static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003419
3420///////////////////////////////////////////////////////////////////////////////////////////////////
3421
3422SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3423 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3424 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3425 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3426 SkIPoint origin = dev->getOrigin();
3427 SkMatrix ctm = this->getTotalMatrix();
3428 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3429
3430 SkIRect clip = fMCRec->fRasterClip.getBounds();
3431 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003432 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003433 clip.setEmpty();
3434 }
3435
3436 fAllocator->updateHandle(handle, ctm, clip);
3437 return handle;
3438 }
3439 return nullptr;
3440}
3441
3442static bool install(SkBitmap* bm, const SkImageInfo& info,
3443 const SkRasterHandleAllocator::Rec& rec) {
3444 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3445 rec.fReleaseProc, rec.fReleaseCtx);
3446}
3447
3448SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3449 SkBitmap* bm) {
3450 SkRasterHandleAllocator::Rec rec;
3451 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3452 return nullptr;
3453 }
3454 return rec.fHandle;
3455}
3456
3457std::unique_ptr<SkCanvas>
3458SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3459 const SkImageInfo& info, const Rec* rec) {
3460 if (!alloc || !supported_for_raster_canvas(info)) {
3461 return nullptr;
3462 }
3463
3464 SkBitmap bm;
3465 Handle hndl;
3466
3467 if (rec) {
3468 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3469 } else {
3470 hndl = alloc->allocBitmap(info, &bm);
3471 }
3472 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3473}