blob: d2bfb59f84b633b5d3270b2746d1f31d626594c6 [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:
Mike Reed99330ba2017-02-22 11:01:08 -0500330 SkDrawIter(SkCanvas* canvas) : fDevice(nullptr) {
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
reed1e7f5e72016-04-27 07:49:17 -0700383 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000384 int getX() const { return fDevice->getOrigin().x(); }
385 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000386 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000387 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000388
Mike Reed99330ba2017-02-22 11:01:08 -0500389 SkBaseDevice* fDevice;
390
reed@android.com8a1c16f2008-12-17 15:59:43 +0000391private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392 const DeviceCM* fCurrLayer;
393 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700394 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000395
396 typedef SkDraw INHERITED;
397};
398
Mike Reed7627fa52017-02-08 10:07:53 -0500399#define FOR_EACH_TOP_DEVICE( code ) \
400 do { \
401 DeviceCM* layer = fMCRec->fTopLayer; \
402 while (layer) { \
403 SkBaseDevice* device = layer->fDevice; \
Mike Reedc42a1cd2017-02-14 14:25:14 -0500404 if (device) { \
405 code; \
406 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500407 layer = layer->fNext; \
408 } \
409 } while (0)
410
reed@android.com8a1c16f2008-12-17 15:59:43 +0000411/////////////////////////////////////////////////////////////////////////////
412
reeddbc3cef2015-04-29 12:18:57 -0700413static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
414 return lazy->isValid() ? lazy->get() : lazy->set(orig);
415}
416
417/**
418 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700419 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700420 */
reedd053ce92016-03-22 10:17:23 -0700421static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700422 SkImageFilter* imgf = paint.getImageFilter();
423 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700424 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700425 }
426
reedd053ce92016-03-22 10:17:23 -0700427 SkColorFilter* imgCFPtr;
428 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700429 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700430 }
reedd053ce92016-03-22 10:17:23 -0700431 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700432
433 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700434 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700435 // there is no existing paint colorfilter, so we can just return the imagefilter's
436 return imgCF;
437 }
438
439 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
440 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700441 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700442}
443
senorblanco87e066e2015-10-28 11:23:36 -0700444/**
445 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
446 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
447 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
448 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
449 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
450 * conservative "effective" bounds based on the settings in the paint... with one exception. This
451 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
452 * deliberately ignored.
453 */
454static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
455 const SkRect& rawBounds,
456 SkRect* storage) {
457 SkPaint tmpUnfiltered(paint);
458 tmpUnfiltered.setImageFilter(nullptr);
459 if (tmpUnfiltered.canComputeFastBounds()) {
460 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
461 } else {
462 return rawBounds;
463 }
464}
465
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466class AutoDrawLooper {
467public:
senorblanco87e066e2015-10-28 11:23:36 -0700468 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
469 // paint. It's used to determine the size of the offscreen layer for filters.
470 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700471 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700472 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000473 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800474#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000475 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800476#else
477 fFilter = nullptr;
478#endif
reed4a8126e2014-09-22 07:29:03 -0700479 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000480 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700481 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000482 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000483
reedd053ce92016-03-22 10:17:23 -0700484 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700485 if (simplifiedCF) {
486 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700487 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700488 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700489 fPaint = paint;
490 }
491
492 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700493 /**
494 * We implement ImageFilters for a given draw by creating a layer, then applying the
495 * imagefilter to the pixels of that layer (its backing surface/image), and then
496 * we call restore() to xfer that layer to the main canvas.
497 *
498 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
499 * 2. Generate the src pixels:
500 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
501 * return (fPaint). We then draw the primitive (using srcover) into a cleared
502 * buffer/surface.
503 * 3. Restore the layer created in #1
504 * The imagefilter is passed the buffer/surface from the layer (now filled with the
505 * src pixels of the primitive). It returns a new "filtered" buffer, which we
506 * draw onto the previous layer using the xfermode from the original paint.
507 */
reed@google.com8926b162012-03-23 15:36:36 +0000508 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500509 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700510 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700511 SkRect storage;
512 if (rawBounds) {
513 // Make rawBounds include all paint outsets except for those due to image filters.
514 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
515 }
reedbfd5f172016-01-07 11:28:08 -0800516 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700517 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700518 fTempLayerForImageFilter = true;
519 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000520 }
521
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000522 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500523 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000524 fIsSimple = false;
525 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700526 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000527 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700528 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000529 }
530 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000531
reed@android.com8a1c16f2008-12-17 15:59:43 +0000532 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700533 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000534 fCanvas->internalRestore();
535 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000536 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000537 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000538
reed@google.com4e2b3d32011-04-07 14:18:59 +0000539 const SkPaint& paint() const {
540 SkASSERT(fPaint);
541 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000542 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000543
reed@google.com129ec222012-05-15 13:24:09 +0000544 bool next(SkDrawFilter::Type drawType) {
545 if (fDone) {
546 return false;
547 } else if (fIsSimple) {
548 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000549 return !fPaint->nothingToDraw();
550 } else {
551 return this->doNext(drawType);
552 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000553 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000554
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500556 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700557 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000558 SkCanvas* fCanvas;
559 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000560 SkDrawFilter* fFilter;
561 const SkPaint* fPaint;
562 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700563 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000564 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000565 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000566 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500567 char fStorage[48];
568 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000569
570 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571};
572
reed@google.com129ec222012-05-15 13:24:09 +0000573bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700574 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000575 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700576 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000577
reeddbc3cef2015-04-29 12:18:57 -0700578 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
579 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000580
reed5c476fb2015-04-20 08:04:21 -0700581 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700582 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700583 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000584 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000585
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000586 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000587 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000588 return false;
589 }
590 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000591 if (!fFilter->filter(paint, drawType)) {
592 fDone = true;
593 return false;
594 }
halcanary96fcdcc2015-08-27 07:41:13 -0700595 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000596 // no looper means we only draw once
597 fDone = true;
598 }
599 }
600 fPaint = paint;
601
602 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000603 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000604 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000605 }
606
607 // call this after any possible paint modifiers
608 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700609 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000610 return false;
611 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000612 return true;
613}
614
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615////////// macros to place around the internal draw calls //////////////////
616
reed3aafe112016-08-18 12:45:34 -0700617#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
618 this->predrawNotify(); \
619 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
620 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800621 SkDrawIter iter(this);
622
623
reed@google.com8926b162012-03-23 15:36:36 +0000624#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000625 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700626 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000627 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000628 SkDrawIter iter(this);
629
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000630#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000631 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700632 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000633 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000634 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000635
reedc83a2972015-07-16 07:40:45 -0700636#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
637 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700638 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700639 while (looper.next(type)) { \
640 SkDrawIter iter(this);
641
reed@google.com4e2b3d32011-04-07 14:18:59 +0000642#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643
644////////////////////////////////////////////////////////////////////////////
645
msarettfbfa2582016-08-12 08:29:08 -0700646static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
647 if (bounds.isEmpty()) {
648 return SkRect::MakeEmpty();
649 }
650
651 // Expand bounds out by 1 in case we are anti-aliasing. We store the
652 // bounds as floats to enable a faster quick reject implementation.
653 SkRect dst;
654 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
655 return dst;
656}
657
mtkleinfeaadee2015-04-08 11:25:48 -0700658void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
659 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700660 fClipStack->reset();
661 fMCRec->reset(bounds);
662
663 // We're peering through a lot of structs here. Only at this scope do we
664 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
665 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700666 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700667 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700668}
669
reedd9544982014-09-09 18:46:22 -0700670SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800671 if (device && device->forceConservativeRasterClip()) {
672 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
673 }
674 // Since init() is only called once by our constructors, it is safe to perform this
675 // const-cast.
676 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
677
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000678 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700679 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800680 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700681 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700682#ifdef SK_EXPERIMENTAL_SHADOWING
683 fLights = nullptr;
684#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000685
halcanary385fe4d2015-08-26 13:07:48 -0700686 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700687
reed@android.com8a1c16f2008-12-17 15:59:43 +0000688 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700689 new (fMCRec) MCRec(fConservativeRasterClip);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500690 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700691 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692
reeda499f902015-05-01 09:34:31 -0700693 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
694 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700695 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700696 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700697
reed@android.com8a1c16f2008-12-17 15:59:43 +0000698 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699
halcanary96fcdcc2015-08-27 07:41:13 -0700700 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000701
reedf92c8662014-08-18 08:02:43 -0700702 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700703 // The root device and the canvas should always have the same pixel geometry
704 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700705 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800706 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700707 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500708
709#ifdef SK_USE_DEVICE_CLIPPING
710 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
711#endif
reedf92c8662014-08-18 08:02:43 -0700712 }
msarettfbfa2582016-08-12 08:29:08 -0700713
reedf92c8662014-08-18 08:02:43 -0700714 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000715}
716
reed@google.comcde92112011-07-06 20:00:52 +0000717SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000718 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700719 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800720 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000721{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000722 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000723
halcanary96fcdcc2015-08-27 07:41:13 -0700724 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000725}
726
reedd9544982014-09-09 18:46:22 -0700727static SkBitmap make_nopixels(int width, int height) {
728 SkBitmap bitmap;
729 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
730 return bitmap;
731}
732
733class SkNoPixelsBitmapDevice : public SkBitmapDevice {
734public:
robertphillipsfcf78292015-06-19 11:49:52 -0700735 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
736 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800737 {
Mike Reedc42a1cd2017-02-14 14:25:14 -0500738 this->setOrigin(SkMatrix::I(), bounds.x(), bounds.y());
reed78e27682014-11-19 08:04:34 -0800739 }
reedd9544982014-09-09 18:46:22 -0700740
741private:
piotaixrb5fae932014-09-24 13:03:30 -0700742
reedd9544982014-09-09 18:46:22 -0700743 typedef SkBitmapDevice INHERITED;
744};
745
reed96a857e2015-01-25 10:33:58 -0800746SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000747 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800748 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800749 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000750{
751 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700752
halcanary385fe4d2015-08-26 13:07:48 -0700753 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
754 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700755}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000756
reed78e27682014-11-19 08:04:34 -0800757SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700758 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700759 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800760 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700761{
762 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700763
halcanary385fe4d2015-08-26 13:07:48 -0700764 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700765}
766
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000767SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000768 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700769 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800770 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000771{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700773
reedd9544982014-09-09 18:46:22 -0700774 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000775}
776
robertphillipsfcf78292015-06-19 11:49:52 -0700777SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
778 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700779 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800780 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700781{
782 inc_canvas();
783
784 this->init(device, flags);
785}
786
reed4a8126e2014-09-22 07:29:03 -0700787SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700788 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700789 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800790 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700791{
792 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700793
Hal Canary704cd322016-11-07 14:13:52 -0500794 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
795 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700796}
reed29c857d2014-09-21 10:25:07 -0700797
Mike Reed356f7c22017-01-10 11:58:39 -0500798SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
799 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700800 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
801 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500802 , fAllocator(std::move(alloc))
reed42b73eb2015-11-20 13:42:42 -0800803 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700804{
805 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700806
Mike Reed356f7c22017-01-10 11:58:39 -0500807 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500808 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809}
810
Mike Reed356f7c22017-01-10 11:58:39 -0500811SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
812
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813SkCanvas::~SkCanvas() {
814 // free up the contents of our deque
815 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000816
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817 this->internalRestore(); // restore the last, since we're going away
818
halcanary385fe4d2015-08-26 13:07:48 -0700819 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000820
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821 dec_canvas();
822}
823
fmalita53d9f1c2016-01-25 06:23:54 -0800824#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825SkDrawFilter* SkCanvas::getDrawFilter() const {
826 return fMCRec->fFilter;
827}
828
829SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700830 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
832 return filter;
833}
fmalita77650002016-01-21 18:47:11 -0800834#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000835
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000836SkMetaData& SkCanvas::getMetaData() {
837 // metadata users are rare, so we lazily allocate it. If that changes we
838 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700839 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000840 fMetaData = new SkMetaData;
841 }
842 return *fMetaData;
843}
844
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845///////////////////////////////////////////////////////////////////////////////
846
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000847void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700848 this->onFlush();
849}
850
851void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000852 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000853 if (device) {
854 device->flush();
855 }
856}
857
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000858SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000859 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000860 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
861}
862
senorblancoafc7cce2016-02-02 18:44:15 -0800863SkIRect SkCanvas::getTopLayerBounds() const {
864 SkBaseDevice* d = this->getTopDevice();
865 if (!d) {
866 return SkIRect::MakeEmpty();
867 }
868 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
869}
870
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000871SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000872 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000873 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874 SkASSERT(rec && rec->fLayer);
875 return rec->fLayer->fDevice;
876}
877
Florin Malita0ed3b642017-01-13 16:56:38 +0000878SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000879 return fMCRec->fTopLayer->fDevice;
880}
881
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000882bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000883 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700884 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700885 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000886 return false;
887 }
888 weAllocated = true;
889 }
890
reedcf01e312015-05-23 19:14:51 -0700891 SkAutoPixmapUnlock unlocker;
892 if (bitmap->requestLock(&unlocker)) {
893 const SkPixmap& pm = unlocker.pixmap();
894 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
895 return true;
896 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000897 }
898
899 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500900 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000901 }
902 return false;
903}
reed@google.com51df9e32010-12-23 19:29:18 +0000904
bsalomon@google.comc6980972011-11-02 19:57:21 +0000905bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000906 SkIRect r = srcRect;
907 const SkISize size = this->getBaseLayerSize();
908 if (!r.intersect(0, 0, size.width(), size.height())) {
909 bitmap->reset();
910 return false;
911 }
912
reed84825042014-09-02 12:50:45 -0700913 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000914 // bitmap will already be reset.
915 return false;
916 }
917 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
918 bitmap->reset();
919 return false;
920 }
921 return true;
922}
923
reed96472de2014-12-10 09:53:42 -0800924bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000925 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000926 if (!device) {
927 return false;
928 }
mtkleinf0f14112014-12-12 08:46:25 -0800929
Matt Sarett03dd6d52017-01-23 12:15:09 -0500930 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000931}
932
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000933bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700934 SkAutoPixmapUnlock unlocker;
935 if (bitmap.requestLock(&unlocker)) {
936 const SkPixmap& pm = unlocker.pixmap();
937 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000938 }
939 return false;
940}
941
Matt Sarett03dd6d52017-01-23 12:15:09 -0500942bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000943 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000944 SkBaseDevice* device = this->getDevice();
945 if (!device) {
946 return false;
947 }
948
Matt Sarett03dd6d52017-01-23 12:15:09 -0500949 // This check gives us an early out and prevents generation ID churn on the surface.
950 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
951 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
952 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
953 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000954 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000955
Matt Sarett03dd6d52017-01-23 12:15:09 -0500956 // Tell our owning surface to bump its generation ID.
957 const bool completeOverwrite =
958 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700959 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700960
Matt Sarett03dd6d52017-01-23 12:15:09 -0500961 // This can still fail, most notably in the case of a invalid color type or alpha type
962 // conversion. We could pull those checks into this function and avoid the unnecessary
963 // generation ID bump. But then we would be performing those checks twice, since they
964 // are also necessary at the bitmap/pixmap entry points.
965 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000966}
reed@google.com51df9e32010-12-23 19:29:18 +0000967
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968//////////////////////////////////////////////////////////////////////////////
969
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970void SkCanvas::updateDeviceCMCache() {
971 if (fDeviceCMDirty) {
972 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700973 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000975
halcanary96fcdcc2015-08-27 07:41:13 -0700976 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700977 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000979 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980 do {
reedde6c5312016-09-02 12:10:07 -0700981 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700982 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000983 }
984 fDeviceCMDirty = false;
985 }
986}
987
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988///////////////////////////////////////////////////////////////////////////////
989
reed2ff1fce2014-12-11 07:07:37 -0800990void SkCanvas::checkForDeferredSave() {
991 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800992 this->doSave();
993 }
994}
995
reedf0090cb2014-11-26 08:55:51 -0800996int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800997#ifdef SK_DEBUG
998 int count = 0;
999 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1000 for (;;) {
1001 const MCRec* rec = (const MCRec*)iter.next();
1002 if (!rec) {
1003 break;
1004 }
1005 count += 1 + rec->fDeferredSaveCount;
1006 }
1007 SkASSERT(count == fSaveCount);
1008#endif
1009 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001010}
1011
1012int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001013 fSaveCount += 1;
1014 fMCRec->fDeferredSaveCount += 1;
1015 return this->getSaveCount() - 1; // return our prev value
1016}
1017
1018void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001019 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001020
1021 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1022 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001023 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001024}
1025
1026void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001027 if (fMCRec->fDeferredSaveCount > 0) {
1028 SkASSERT(fSaveCount > 1);
1029 fSaveCount -= 1;
1030 fMCRec->fDeferredSaveCount -= 1;
1031 } else {
1032 // check for underflow
1033 if (fMCStack.count() > 1) {
1034 this->willRestore();
1035 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001036 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001037 this->internalRestore();
1038 this->didRestore();
1039 }
reedf0090cb2014-11-26 08:55:51 -08001040 }
1041}
1042
1043void SkCanvas::restoreToCount(int count) {
1044 // sanity check
1045 if (count < 1) {
1046 count = 1;
1047 }
mtkleinf0f14112014-12-12 08:46:25 -08001048
reedf0090cb2014-11-26 08:55:51 -08001049 int n = this->getSaveCount() - count;
1050 for (int i = 0; i < n; ++i) {
1051 this->restore();
1052 }
1053}
1054
reed2ff1fce2014-12-11 07:07:37 -08001055void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001057 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001059
reed687fa1c2015-04-07 08:00:56 -07001060 fClipStack->save();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001061#ifdef SK_USE_DEVICE_CLIPPING
1062 FOR_EACH_TOP_DEVICE(device->save());
1063#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064}
1065
reed4960eee2015-12-18 07:09:18 -08001066bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001067 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001068}
1069
reed4960eee2015-12-18 07:09:18 -08001070bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001071 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -05001072 SkIRect clipBounds = this->getDeviceClipBounds();
1073 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001074 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001075 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001076
reed96e657d2015-03-10 17:30:07 -07001077 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1078
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001079 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001080 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001081 if (bounds && !imageFilter->canComputeFastBounds()) {
1082 bounds = nullptr;
1083 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001084 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001085 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001086 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001088
reed96e657d2015-03-10 17:30:07 -07001089 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090 r.roundOut(&ir);
1091 // early exit if the layer's bounds are clipped out
1092 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001093 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001094 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001095 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001096 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001097 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098 }
1099 } else { // no user bounds, so just use the clip
1100 ir = clipBounds;
1101 }
reed180aec42015-03-11 10:39:04 -07001102 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001103
reed4960eee2015-12-18 07:09:18 -08001104 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001105 // Simplify the current clips since they will be applied properly during restore()
Mike Reedc1f77742016-12-09 09:00:50 -05001106 fClipStack->clipDevRect(ir, kReplace_SkClipOp);
reed180aec42015-03-11 10:39:04 -07001107 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001108 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001109 }
1110
1111 if (intersection) {
1112 *intersection = ir;
1113 }
1114 return true;
1115}
1116
reed4960eee2015-12-18 07:09:18 -08001117
reed4960eee2015-12-18 07:09:18 -08001118int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1119 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001120}
1121
reed70ee31b2015-12-10 13:44:45 -08001122int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001123 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1124}
1125
1126int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1127 SaveLayerRec rec(origRec);
1128 if (gIgnoreSaveLayerBounds) {
1129 rec.fBounds = nullptr;
1130 }
1131 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1132 fSaveCount += 1;
1133 this->internalSaveLayer(rec, strategy);
1134 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001135}
1136
reeda2217ef2016-07-20 06:04:34 -07001137void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001138 SkBaseDevice* dst, const SkIPoint& dstOrigin,
1139 const SkMatrix& ctm, const SkClipStack* clipStack) {
reeda2217ef2016-07-20 06:04:34 -07001140 SkDraw draw;
1141 SkRasterClip rc;
1142 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1143 if (!dst->accessPixels(&draw.fDst)) {
1144 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001145 }
reeda2217ef2016-07-20 06:04:34 -07001146 draw.fMatrix = &SkMatrix::I();
1147 draw.fRC = &rc;
1148 draw.fClipStack = clipStack;
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()) {
Stan Iliev4eabd5d2017-02-21 11:15:53 -05001872 const SkClipStack* cs = this->getClipStack();
1873 SkClipStack::BoundsType boundType;
1874 bool isIntersectionOfRects;
1875 SkRect bounds;
1876 cs->getBounds(&bounds, &boundType, &isIntersectionOfRects);
1877 if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
1878 rgn->setRect(bounds.round());
1879 return;
1880 }
Mike Reed3726a4a2017-01-19 11:36:41 -05001881 SkPath path;
Stan Iliev4eabd5d2017-02-21 11:15:53 -05001882 cs->asPath(&path);
Mike Reed3726a4a2017-01-19 11:36:41 -05001883 SkISize size = this->getBaseLayerSize();
1884 rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
1885 } else {
1886 *rgn = fMCRec->fRasterClip.forceGetBW();
1887 }
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001888}
1889
Brian Osman11052242016-10-27 14:47:55 -04001890GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001891 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001892 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001893}
1894
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001895GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001896 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001897 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001898}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001899
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001900void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1901 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001902 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001903 if (outer.isEmpty()) {
1904 return;
1905 }
1906 if (inner.isEmpty()) {
1907 this->drawRRect(outer, paint);
1908 return;
1909 }
1910
1911 // We don't have this method (yet), but technically this is what we should
1912 // be able to assert...
1913 // SkASSERT(outer.contains(inner));
1914 //
1915 // For now at least check for containment of bounds
1916 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1917
1918 this->onDrawDRRect(outer, inner, paint);
1919}
1920
reed41af9662015-01-05 07:49:08 -08001921// These need to stop being virtual -- clients need to override the onDraw... versions
1922
1923void SkCanvas::drawPaint(const SkPaint& paint) {
1924 this->onDrawPaint(paint);
1925}
1926
1927void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1928 this->onDrawRect(r, paint);
1929}
1930
msarettdca352e2016-08-26 06:37:45 -07001931void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1932 if (region.isEmpty()) {
1933 return;
1934 }
1935
1936 if (region.isRect()) {
1937 return this->drawIRect(region.getBounds(), paint);
1938 }
1939
1940 this->onDrawRegion(region, paint);
1941}
1942
reed41af9662015-01-05 07:49:08 -08001943void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1944 this->onDrawOval(r, paint);
1945}
1946
1947void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1948 this->onDrawRRect(rrect, paint);
1949}
1950
1951void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1952 this->onDrawPoints(mode, count, pts, paint);
1953}
1954
1955void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001956 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001957 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001958 this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices,
1959 indexCount, paint);
1960}
1961
1962void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint,
1963 uint32_t flags) {
1964 RETURN_ON_NULL(vertices);
1965 this->onDrawVerticesObject(std::move(vertices), mode, paint, flags);
reed41af9662015-01-05 07:49:08 -08001966}
1967
1968void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1969 this->onDrawPath(path, paint);
1970}
1971
reeda85d4d02015-05-06 12:56:48 -07001972void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001973 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001974 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001975}
1976
reede47829b2015-08-06 10:02:53 -07001977void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, 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 if (dst.isEmpty() || src.isEmpty()) {
1981 return;
1982 }
1983 this->onDrawImageRect(image, &src, dst, paint, constraint);
1984}
reed41af9662015-01-05 07:49:08 -08001985
reed84984ef2015-07-17 07:09:43 -07001986void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1987 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001988 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001989 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001990}
1991
reede47829b2015-08-06 10:02:53 -07001992void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1993 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001994 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001995 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1996 constraint);
1997}
reede47829b2015-08-06 10:02:53 -07001998
reed4c21dc52015-06-25 12:32:03 -07001999void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2000 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002001 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07002002 if (dst.isEmpty()) {
2003 return;
2004 }
msarett552bca92016-08-03 06:53:26 -07002005 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
2006 this->onDrawImageNine(image, center, dst, paint);
2007 } else {
reede47829b2015-08-06 10:02:53 -07002008 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002009 }
reed4c21dc52015-06-25 12:32:03 -07002010}
2011
msarett16882062016-08-16 09:31:08 -07002012void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2013 const SkPaint* paint) {
2014 RETURN_ON_NULL(image);
2015 if (dst.isEmpty()) {
2016 return;
2017 }
msarett71df2d72016-09-30 12:41:42 -07002018
2019 SkIRect bounds;
2020 Lattice latticePlusBounds = lattice;
2021 if (!latticePlusBounds.fBounds) {
2022 bounds = SkIRect::MakeWH(image->width(), image->height());
2023 latticePlusBounds.fBounds = &bounds;
2024 }
2025
2026 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
2027 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07002028 } else {
2029 this->drawImageRect(image, dst, paint);
2030 }
2031}
2032
reed41af9662015-01-05 07:49:08 -08002033void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002034 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002035 return;
2036 }
reed41af9662015-01-05 07:49:08 -08002037 this->onDrawBitmap(bitmap, dx, dy, paint);
2038}
2039
reede47829b2015-08-06 10:02:53 -07002040void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002041 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002042 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002043 return;
2044 }
reede47829b2015-08-06 10:02:53 -07002045 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002046}
2047
reed84984ef2015-07-17 07:09:43 -07002048void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2049 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002050 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002051}
2052
reede47829b2015-08-06 10:02:53 -07002053void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2054 SrcRectConstraint constraint) {
2055 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2056 constraint);
2057}
reede47829b2015-08-06 10:02:53 -07002058
reed41af9662015-01-05 07:49:08 -08002059void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2060 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002061 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002062 return;
2063 }
msarett552bca92016-08-03 06:53:26 -07002064 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2065 this->onDrawBitmapNine(bitmap, center, dst, paint);
2066 } else {
reeda5517e22015-07-14 10:54:12 -07002067 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002068 }
reed41af9662015-01-05 07:49:08 -08002069}
2070
msarettc573a402016-08-02 08:05:56 -07002071void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2072 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002073 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002074 return;
2075 }
msarett71df2d72016-09-30 12:41:42 -07002076
2077 SkIRect bounds;
2078 Lattice latticePlusBounds = lattice;
2079 if (!latticePlusBounds.fBounds) {
2080 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2081 latticePlusBounds.fBounds = &bounds;
2082 }
2083
2084 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2085 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002086 } else {
msarett16882062016-08-16 09:31:08 -07002087 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002088 }
msarettc573a402016-08-02 08:05:56 -07002089}
2090
reed71c3c762015-06-24 10:29:17 -07002091void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002092 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002093 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002094 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002095 if (count <= 0) {
2096 return;
2097 }
Joe Gregorioc4859072017-01-20 14:21:27 +00002098 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002099 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002100 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002101}
2102
reedf70b5312016-03-04 16:36:20 -08002103void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2104 if (key) {
2105 this->onDrawAnnotation(rect, key, value);
2106 }
2107}
2108
reede47829b2015-08-06 10:02:53 -07002109void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2110 const SkPaint* paint, SrcRectConstraint constraint) {
2111 if (src) {
2112 this->drawImageRect(image, *src, dst, paint, constraint);
2113 } else {
2114 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2115 dst, paint, constraint);
2116 }
2117}
2118void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2119 const SkPaint* paint, SrcRectConstraint constraint) {
2120 if (src) {
2121 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2122 } else {
2123 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2124 dst, paint, constraint);
2125 }
2126}
2127
tomhudsoncb3bd182016-05-18 07:24:16 -07002128void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2129 SkIRect layer_bounds = this->getTopLayerBounds();
2130 if (matrix) {
2131 *matrix = this->getTotalMatrix();
2132 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2133 }
2134 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05002135 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07002136 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2137 }
2138}
2139
reed@android.com8a1c16f2008-12-17 15:59:43 +00002140//////////////////////////////////////////////////////////////////////////////
2141// These are the virtual drawing methods
2142//////////////////////////////////////////////////////////////////////////////
2143
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002144void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002145 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002146 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2147 }
2148}
2149
reed41af9662015-01-05 07:49:08 -08002150void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002151 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002152 this->internalDrawPaint(paint);
2153}
2154
2155void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002156 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002157
2158 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002159 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002160 }
2161
reed@google.com4e2b3d32011-04-07 14:18:59 +00002162 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002163}
2164
reed41af9662015-01-05 07:49:08 -08002165void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2166 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002167 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002168 if ((long)count <= 0) {
2169 return;
2170 }
2171
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002172 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002173 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002174 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002175 // special-case 2 points (common for drawing a single line)
2176 if (2 == count) {
2177 r.set(pts[0], pts[1]);
2178 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002179 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002180 }
senorblanco87e066e2015-10-28 11:23:36 -07002181 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2182 return;
2183 }
2184 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002185 }
reed@google.coma584aed2012-05-16 14:06:02 +00002186
halcanary96fcdcc2015-08-27 07:41:13 -07002187 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002188
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002189 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002190
reed@android.com8a1c16f2008-12-17 15:59:43 +00002191 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002192 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002193 }
reed@google.com4b226022011-01-11 18:32:13 +00002194
reed@google.com4e2b3d32011-04-07 14:18:59 +00002195 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002196}
2197
reed4a167172016-08-18 17:15:25 -07002198static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2199 return ((intptr_t)paint.getImageFilter() |
2200#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2201 (intptr_t)canvas->getDrawFilter() |
2202#endif
2203 (intptr_t)paint.getLooper() ) != 0;
2204}
2205
reed41af9662015-01-05 07:49:08 -08002206void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002207 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002208 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002209 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002210 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002211 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2212 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2213 SkRect tmp(r);
2214 tmp.sort();
2215
senorblanco87e066e2015-10-28 11:23:36 -07002216 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2217 return;
2218 }
2219 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002220 }
reed@google.com4b226022011-01-11 18:32:13 +00002221
reed4a167172016-08-18 17:15:25 -07002222 if (needs_autodrawlooper(this, paint)) {
2223 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002224
reed4a167172016-08-18 17:15:25 -07002225 while (iter.next()) {
2226 iter.fDevice->drawRect(iter, r, looper.paint());
2227 }
2228
2229 LOOPER_END
2230 } else {
2231 this->predrawNotify(bounds, &paint, false);
2232 SkDrawIter iter(this);
2233 while (iter.next()) {
2234 iter.fDevice->drawRect(iter, r, paint);
2235 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002236 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002237}
2238
msarett44df6512016-08-25 13:54:30 -07002239void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2240 SkRect storage;
2241 SkRect regionRect = SkRect::Make(region.getBounds());
2242 const SkRect* bounds = nullptr;
2243 if (paint.canComputeFastBounds()) {
2244 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2245 return;
2246 }
2247 bounds = &regionRect;
2248 }
2249
2250 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2251
2252 while (iter.next()) {
2253 iter.fDevice->drawRegion(iter, region, looper.paint());
2254 }
2255
2256 LOOPER_END
2257}
2258
reed41af9662015-01-05 07:49:08 -08002259void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002260 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002261 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002262 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002263 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002264 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2265 return;
2266 }
2267 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002268 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002269
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002270 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002271
2272 while (iter.next()) {
2273 iter.fDevice->drawOval(iter, oval, looper.paint());
2274 }
2275
2276 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002277}
2278
bsalomonac3aa242016-08-19 11:25:19 -07002279void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2280 SkScalar sweepAngle, bool useCenter,
2281 const SkPaint& paint) {
2282 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2283 const SkRect* bounds = nullptr;
2284 if (paint.canComputeFastBounds()) {
2285 SkRect storage;
2286 // Note we're using the entire oval as the bounds.
2287 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2288 return;
2289 }
2290 bounds = &oval;
2291 }
2292
2293 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2294
2295 while (iter.next()) {
2296 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2297 }
2298
2299 LOOPER_END
2300}
2301
reed41af9662015-01-05 07:49:08 -08002302void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002303 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002304 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002305 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002306 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002307 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2308 return;
2309 }
2310 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002311 }
2312
2313 if (rrect.isRect()) {
2314 // call the non-virtual version
2315 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002316 return;
2317 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002318 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002319 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2320 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002321 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002322
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002323 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002324
2325 while (iter.next()) {
2326 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2327 }
2328
2329 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002330}
2331
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002332void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2333 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002334 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002335 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002336 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002337 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2338 return;
2339 }
2340 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002341 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002342
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002343 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002344
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002345 while (iter.next()) {
2346 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2347 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002348
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002349 LOOPER_END
2350}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002351
reed41af9662015-01-05 07:49:08 -08002352void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002353 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002354 if (!path.isFinite()) {
2355 return;
2356 }
2357
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002358 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002359 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002360 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002361 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002362 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2363 return;
2364 }
2365 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002366 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002367
2368 const SkRect& r = path.getBounds();
2369 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002370 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002371 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002372 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002373 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002374 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002375
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002376 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002377
2378 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002379 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002380 }
2381
reed@google.com4e2b3d32011-04-07 14:18:59 +00002382 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002383}
2384
reed262a71b2015-12-05 13:07:27 -08002385bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002386 if (!paint.getImageFilter()) {
2387 return false;
2388 }
2389
2390 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002391 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002392 return false;
2393 }
2394
2395 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2396 // Once we can filter and the filter will return a result larger than itself, we should be
2397 // able to remove this constraint.
2398 // skbug.com/4526
2399 //
2400 SkPoint pt;
2401 ctm.mapXY(x, y, &pt);
2402 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2403 return ir.contains(fMCRec->fRasterClip.getBounds());
2404}
2405
reeda85d4d02015-05-06 12:56:48 -07002406void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002407 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002408 SkRect bounds = SkRect::MakeXYWH(x, y,
2409 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002410 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002411 SkRect tmp = bounds;
2412 if (paint) {
2413 paint->computeFastBounds(tmp, &tmp);
2414 }
2415 if (this->quickReject(tmp)) {
2416 return;
2417 }
reeda85d4d02015-05-06 12:56:48 -07002418 }
halcanary9d524f22016-03-29 09:03:52 -07002419
reeda85d4d02015-05-06 12:56:48 -07002420 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002421 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002422 paint = lazy.init();
2423 }
reed262a71b2015-12-05 13:07:27 -08002424
reeda2217ef2016-07-20 06:04:34 -07002425 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002426 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2427 *paint);
2428 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002429 special = this->getDevice()->makeSpecial(image);
2430 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002431 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002432 }
2433 }
2434
reed262a71b2015-12-05 13:07:27 -08002435 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2436
reeda85d4d02015-05-06 12:56:48 -07002437 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002438 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002439 if (special) {
2440 SkPoint pt;
2441 iter.fMatrix->mapXY(x, y, &pt);
2442 iter.fDevice->drawSpecial(iter, special.get(),
2443 SkScalarRoundToInt(pt.fX),
2444 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002445 } else {
2446 iter.fDevice->drawImage(iter, image, x, y, pnt);
2447 }
reeda85d4d02015-05-06 12:56:48 -07002448 }
halcanary9d524f22016-03-29 09:03:52 -07002449
reeda85d4d02015-05-06 12:56:48 -07002450 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002451}
2452
reed41af9662015-01-05 07:49:08 -08002453void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002454 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002455 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002456 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002457 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002458 if (paint) {
2459 paint->computeFastBounds(dst, &storage);
2460 }
2461 if (this->quickReject(storage)) {
2462 return;
2463 }
reeda85d4d02015-05-06 12:56:48 -07002464 }
2465 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002466 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002467 paint = lazy.init();
2468 }
halcanary9d524f22016-03-29 09:03:52 -07002469
senorblancoc41e7e12015-12-07 12:51:30 -08002470 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002471 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002472
reeda85d4d02015-05-06 12:56:48 -07002473 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002474 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002475 }
halcanary9d524f22016-03-29 09:03:52 -07002476
reeda85d4d02015-05-06 12:56:48 -07002477 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002478}
2479
reed41af9662015-01-05 07:49:08 -08002480void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002481 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482 SkDEBUGCODE(bitmap.validate();)
2483
reed33366972015-10-08 09:22:02 -07002484 if (bitmap.drawsNothing()) {
2485 return;
2486 }
2487
2488 SkLazyPaint lazy;
2489 if (nullptr == paint) {
2490 paint = lazy.init();
2491 }
2492
2493 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2494
2495 SkRect storage;
2496 const SkRect* bounds = nullptr;
2497 if (paint->canComputeFastBounds()) {
2498 bitmap.getBounds(&storage);
2499 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002500 SkRect tmp = storage;
2501 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2502 return;
2503 }
2504 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002505 }
reed@google.com4b226022011-01-11 18:32:13 +00002506
reeda2217ef2016-07-20 06:04:34 -07002507 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002508 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2509 *paint);
2510 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002511 special = this->getDevice()->makeSpecial(bitmap);
2512 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002513 drawAsSprite = false;
2514 }
2515 }
2516
reed262a71b2015-12-05 13:07:27 -08002517 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002518
2519 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002520 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002521 if (special) {
reed262a71b2015-12-05 13:07:27 -08002522 SkPoint pt;
2523 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002524 iter.fDevice->drawSpecial(iter, special.get(),
2525 SkScalarRoundToInt(pt.fX),
2526 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002527 } else {
2528 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2529 }
reed33366972015-10-08 09:22:02 -07002530 }
msarettfbfa2582016-08-12 08:29:08 -07002531
reed33366972015-10-08 09:22:02 -07002532 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002533}
2534
reed@google.com9987ec32011-09-07 11:57:52 +00002535// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002536void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002537 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002538 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002539 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002540 return;
2541 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002542
halcanary96fcdcc2015-08-27 07:41:13 -07002543 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002544 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002545 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2546 return;
2547 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002548 }
reed@google.com3d608122011-11-21 15:16:16 +00002549
reed@google.com33535f32012-09-25 15:37:50 +00002550 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002551 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002552 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002553 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002554
senorblancoc41e7e12015-12-07 12:51:30 -08002555 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002556 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002557
reed@google.com33535f32012-09-25 15:37:50 +00002558 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002559 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002560 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002561
reed@google.com33535f32012-09-25 15:37:50 +00002562 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002563}
2564
reed41af9662015-01-05 07:49:08 -08002565void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002566 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002567 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002568 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002569 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002570}
2571
reed4c21dc52015-06-25 12:32:03 -07002572void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2573 const SkPaint* paint) {
2574 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002575
halcanary96fcdcc2015-08-27 07:41:13 -07002576 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002577 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002578 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2579 return;
2580 }
reed@google.com3d608122011-11-21 15:16:16 +00002581 }
halcanary9d524f22016-03-29 09:03:52 -07002582
reed4c21dc52015-06-25 12:32:03 -07002583 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002584 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002585 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002586 }
halcanary9d524f22016-03-29 09:03:52 -07002587
senorblancoc41e7e12015-12-07 12:51:30 -08002588 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002589
reed4c21dc52015-06-25 12:32:03 -07002590 while (iter.next()) {
2591 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002592 }
halcanary9d524f22016-03-29 09:03:52 -07002593
reed4c21dc52015-06-25 12:32:03 -07002594 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002595}
2596
reed41af9662015-01-05 07:49:08 -08002597void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2598 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002599 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002600 SkDEBUGCODE(bitmap.validate();)
2601
halcanary96fcdcc2015-08-27 07:41:13 -07002602 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002603 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002604 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2605 return;
2606 }
reed4c21dc52015-06-25 12:32:03 -07002607 }
halcanary9d524f22016-03-29 09:03:52 -07002608
reed4c21dc52015-06-25 12:32:03 -07002609 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002610 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002611 paint = lazy.init();
2612 }
halcanary9d524f22016-03-29 09:03:52 -07002613
senorblancoc41e7e12015-12-07 12:51:30 -08002614 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002615
reed4c21dc52015-06-25 12:32:03 -07002616 while (iter.next()) {
2617 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2618 }
halcanary9d524f22016-03-29 09:03:52 -07002619
reed4c21dc52015-06-25 12:32:03 -07002620 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002621}
2622
msarett16882062016-08-16 09:31:08 -07002623void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2624 const SkPaint* paint) {
2625 if (nullptr == paint || paint->canComputeFastBounds()) {
2626 SkRect storage;
2627 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2628 return;
2629 }
2630 }
2631
2632 SkLazyPaint lazy;
2633 if (nullptr == paint) {
2634 paint = lazy.init();
2635 }
2636
2637 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2638
2639 while (iter.next()) {
2640 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2641 }
2642
2643 LOOPER_END
2644}
2645
2646void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2647 const SkRect& dst, const SkPaint* paint) {
2648 if (nullptr == paint || paint->canComputeFastBounds()) {
2649 SkRect storage;
2650 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2651 return;
2652 }
2653 }
2654
2655 SkLazyPaint lazy;
2656 if (nullptr == paint) {
2657 paint = lazy.init();
2658 }
2659
2660 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2661
2662 while (iter.next()) {
2663 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2664 }
2665
2666 LOOPER_END
2667}
2668
reed@google.comf67e4cf2011-03-15 20:56:58 +00002669class SkDeviceFilteredPaint {
2670public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002671 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002672 uint32_t filteredFlags = device->filterTextFlags(paint);
2673 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002674 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002675 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002676 fPaint = newPaint;
2677 } else {
2678 fPaint = &paint;
2679 }
2680 }
2681
reed@google.comf67e4cf2011-03-15 20:56:58 +00002682 const SkPaint& paint() const { return *fPaint; }
2683
2684private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002685 const SkPaint* fPaint;
2686 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002687};
2688
reed@google.come0d9ce82014-04-23 04:00:17 +00002689void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2690 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002691 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002692
2693 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002694 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002695 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002696 }
2697
reed@google.com4e2b3d32011-04-07 14:18:59 +00002698 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002699}
2700
reed@google.come0d9ce82014-04-23 04:00:17 +00002701void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2702 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002703 SkPoint textOffset = SkPoint::Make(0, 0);
2704
halcanary96fcdcc2015-08-27 07:41:13 -07002705 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002706
reed@android.com8a1c16f2008-12-17 15:59:43 +00002707 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002708 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002709 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002710 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002712
reed@google.com4e2b3d32011-04-07 14:18:59 +00002713 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002714}
2715
reed@google.come0d9ce82014-04-23 04:00:17 +00002716void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2717 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002718
2719 SkPoint textOffset = SkPoint::Make(0, constY);
2720
halcanary96fcdcc2015-08-27 07:41:13 -07002721 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002722
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002724 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002725 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002726 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002728
reed@google.com4e2b3d32011-04-07 14:18:59 +00002729 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730}
2731
reed@google.come0d9ce82014-04-23 04:00:17 +00002732void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2733 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002734 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002735
reed@android.com8a1c16f2008-12-17 15:59:43 +00002736 while (iter.next()) {
2737 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002738 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002739 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002740
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002741 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002742}
2743
reed45561a02016-07-07 12:47:17 -07002744void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2745 const SkRect* cullRect, const SkPaint& paint) {
2746 if (cullRect && this->quickReject(*cullRect)) {
2747 return;
2748 }
2749
2750 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2751
2752 while (iter.next()) {
2753 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2754 }
2755
2756 LOOPER_END
2757}
2758
fmalita00d5c2c2014-08-21 08:53:26 -07002759void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2760 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002761
fmalita85d5eb92015-03-04 11:20:12 -08002762 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002763 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002764 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002765 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002766 SkRect tmp;
2767 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2768 return;
2769 }
2770 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002771 }
2772
fmalita024f9962015-03-03 19:08:17 -08002773 // We cannot filter in the looper as we normally do, because the paint is
2774 // incomplete at this point (text-related attributes are embedded within blob run paints).
2775 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002776 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002777
fmalita85d5eb92015-03-04 11:20:12 -08002778 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002779
fmalitaaa1b9122014-08-28 14:32:24 -07002780 while (iter.next()) {
2781 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002782 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002783 }
2784
fmalitaaa1b9122014-08-28 14:32:24 -07002785 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002786
2787 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002788}
2789
reed@google.come0d9ce82014-04-23 04:00:17 +00002790// These will become non-virtual, so they always call the (virtual) onDraw... method
2791void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2792 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002793 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002794 if (byteLength) {
2795 this->onDrawText(text, byteLength, x, y, paint);
2796 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002797}
2798void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2799 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002800 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002801 if (byteLength) {
2802 this->onDrawPosText(text, byteLength, pos, paint);
2803 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002804}
2805void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2806 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002807 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002808 if (byteLength) {
2809 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2810 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002811}
2812void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2813 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002814 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002815 if (byteLength) {
2816 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2817 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002818}
reed45561a02016-07-07 12:47:17 -07002819void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2820 const SkRect* cullRect, const SkPaint& paint) {
2821 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2822 if (byteLength) {
2823 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2824 }
2825}
fmalita00d5c2c2014-08-21 08:53:26 -07002826void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2827 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002828 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002829 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002830 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002831}
reed@google.come0d9ce82014-04-23 04:00:17 +00002832
reed41af9662015-01-05 07:49:08 -08002833void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2834 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002835 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002836 const uint16_t indices[], int indexCount,
2837 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002838 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002839 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002840
reed@android.com8a1c16f2008-12-17 15:59:43 +00002841 while (iter.next()) {
2842 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002843 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002844 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002845 }
reed@google.com4b226022011-01-11 18:32:13 +00002846
reed@google.com4e2b3d32011-04-07 14:18:59 +00002847 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002848}
2849
Brian Salomon199fb872017-02-06 09:41:10 -05002850void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode,
2851 const SkPaint& paint, uint32_t flags) {
2852 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2853 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2854
2855 while (iter.next()) {
2856 // In the common case of one iteration we could std::move vertices here.
2857 iter.fDevice->drawVerticesObject(iter, vertices, bmode, looper.paint(), flags);
2858 }
2859
2860 LOOPER_END
2861}
2862
2863void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode,
2864 const SkPaint& paint, uint32_t flags) {
2865 const SkPoint* texs =
2866 (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords();
2867 const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors();
2868 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs,
2869 colors, mode, vertices->indices(), vertices->indexCount(), paint);
2870}
2871
dandovb3c9d1c2014-08-12 08:34:29 -07002872void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002873 const SkPoint texCoords[4], SkBlendMode bmode,
2874 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002875 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002876 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002877 return;
2878 }
mtklein6cfa73a2014-08-13 13:33:49 -07002879
Mike Reedfaba3712016-11-03 14:45:31 -04002880 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002881}
2882
2883void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002884 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002885 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002886 // Since a patch is always within the convex hull of the control points, we discard it when its
2887 // bounding rectangle is completely outside the current clip.
2888 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002889 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002890 if (this->quickReject(bounds)) {
2891 return;
2892 }
mtklein6cfa73a2014-08-13 13:33:49 -07002893
halcanary96fcdcc2015-08-27 07:41:13 -07002894 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002895
dandovecfff212014-08-04 10:02:00 -07002896 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002897 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002898 }
mtklein6cfa73a2014-08-13 13:33:49 -07002899
dandovecfff212014-08-04 10:02:00 -07002900 LOOPER_END
2901}
2902
reeda8db7282015-07-07 10:22:31 -07002903void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002904 RETURN_ON_NULL(dr);
2905 if (x || y) {
2906 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2907 this->onDrawDrawable(dr, &matrix);
2908 } else {
2909 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002910 }
2911}
2912
reeda8db7282015-07-07 10:22:31 -07002913void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002914 RETURN_ON_NULL(dr);
2915 if (matrix && matrix->isIdentity()) {
2916 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002917 }
reede3b38ce2016-01-08 09:18:44 -08002918 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002919}
2920
2921void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002922 // drawable bounds are no longer reliable (e.g. android displaylist)
2923 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002924 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002925}
2926
reed71c3c762015-06-24 10:29:17 -07002927void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002928 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002929 const SkRect* cull, const SkPaint* paint) {
2930 if (cull && this->quickReject(*cull)) {
2931 return;
2932 }
2933
2934 SkPaint pnt;
2935 if (paint) {
2936 pnt = *paint;
2937 }
halcanary9d524f22016-03-29 09:03:52 -07002938
halcanary96fcdcc2015-08-27 07:41:13 -07002939 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002940 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002941 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002942 }
2943 LOOPER_END
2944}
2945
reedf70b5312016-03-04 16:36:20 -08002946void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2947 SkASSERT(key);
2948
2949 SkPaint paint;
2950 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2951 while (iter.next()) {
2952 iter.fDevice->drawAnnotation(iter, rect, key, value);
2953 }
2954 LOOPER_END
2955}
2956
reed@android.com8a1c16f2008-12-17 15:59:43 +00002957//////////////////////////////////////////////////////////////////////////////
2958// These methods are NOT virtual, and therefore must call back into virtual
2959// methods, rather than actually drawing themselves.
2960//////////////////////////////////////////////////////////////////////////////
2961
reed374772b2016-10-05 17:33:02 -07002962void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002963 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002964 SkPaint paint;
2965
2966 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002967 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002968 this->drawPaint(paint);
2969}
2970
reed374772b2016-10-05 17:33:02 -07002971void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002972 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002973 SkPaint paint;
2974
2975 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002976 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002977 this->drawPaint(paint);
2978}
2979
2980void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002981 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002982 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002983
reed@android.com8a1c16f2008-12-17 15:59:43 +00002984 pt.set(x, y);
2985 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2986}
2987
2988void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002989 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002990 SkPoint pt;
2991 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002992
reed@android.com8a1c16f2008-12-17 15:59:43 +00002993 pt.set(x, y);
2994 paint.setColor(color);
2995 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2996}
2997
2998void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2999 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003000 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003001 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003002
reed@android.com8a1c16f2008-12-17 15:59:43 +00003003 pts[0].set(x0, y0);
3004 pts[1].set(x1, y1);
3005 this->drawPoints(kLines_PointMode, 2, pts, paint);
3006}
3007
3008void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3009 SkScalar right, SkScalar bottom,
3010 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003011 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003012 SkRect r;
3013
3014 r.set(left, top, right, bottom);
3015 this->drawRect(r, paint);
3016}
3017
3018void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3019 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003020 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003021 if (radius < 0) {
3022 radius = 0;
3023 }
3024
3025 SkRect r;
3026 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003027 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003028}
3029
3030void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3031 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003032 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003033 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003034 SkRRect rrect;
3035 rrect.setRectXY(r, rx, ry);
3036 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003037 } else {
3038 this->drawRect(r, paint);
3039 }
3040}
3041
reed@android.com8a1c16f2008-12-17 15:59:43 +00003042void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3043 SkScalar sweepAngle, bool useCenter,
3044 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003045 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003046 if (oval.isEmpty() || !sweepAngle) {
3047 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003048 }
bsalomon21af9ca2016-08-25 12:29:23 -07003049 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003050}
3051
3052void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3053 const SkPath& path, SkScalar hOffset,
3054 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003055 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003056 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003057
reed@android.com8a1c16f2008-12-17 15:59:43 +00003058 matrix.setTranslate(hOffset, vOffset);
3059 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3060}
3061
reed@android.comf76bacf2009-05-13 14:00:33 +00003062///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003063
3064/**
3065 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3066 * against the playback cost of recursing into the subpicture to get at its actual ops.
3067 *
3068 * For now we pick a conservatively small value, though measurement (and other heuristics like
3069 * the type of ops contained) may justify changing this value.
3070 */
3071#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003072
reedd5fa1a42014-08-09 11:08:05 -07003073void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003074 RETURN_ON_NULL(picture);
3075
reed1c2c4412015-04-30 13:09:24 -07003076 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003077 if (matrix && matrix->isIdentity()) {
3078 matrix = nullptr;
3079 }
3080 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3081 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3082 picture->playback(this);
3083 } else {
3084 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003085 }
3086}
robertphillips9b14f262014-06-04 05:40:44 -07003087
reedd5fa1a42014-08-09 11:08:05 -07003088void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3089 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003090 if (!paint || paint->canComputeFastBounds()) {
3091 SkRect bounds = picture->cullRect();
3092 if (paint) {
3093 paint->computeFastBounds(bounds, &bounds);
3094 }
3095 if (matrix) {
3096 matrix->mapRect(&bounds);
3097 }
3098 if (this->quickReject(bounds)) {
3099 return;
3100 }
3101 }
3102
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003103 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003104 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003105}
3106
vjiaoblack95302da2016-07-21 10:25:54 -07003107#ifdef SK_EXPERIMENTAL_SHADOWING
3108void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3109 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003110 const SkPaint* paint,
3111 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003112 RETURN_ON_NULL(picture);
3113
3114 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3115
vjiaoblacke6f5d562016-08-25 06:30:23 -07003116 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003117}
3118
3119void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3120 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003121 const SkPaint* paint,
3122 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003123 if (!paint || paint->canComputeFastBounds()) {
3124 SkRect bounds = picture->cullRect();
3125 if (paint) {
3126 paint->computeFastBounds(bounds, &bounds);
3127 }
3128 if (matrix) {
3129 matrix->mapRect(&bounds);
3130 }
3131 if (this->quickReject(bounds)) {
3132 return;
3133 }
3134 }
3135
3136 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3137
vjiaoblacke6f5d562016-08-25 06:30:23 -07003138 sk_sp<SkImage> povDepthMap;
3139 sk_sp<SkImage> diffuseMap;
3140
vjiaoblack904527d2016-08-09 09:32:09 -07003141 // povDepthMap
3142 {
3143 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003144 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3145 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003146 sk_sp<SkLights> povLight = builder.finish();
3147
3148 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3149 picture->cullRect().height(),
3150 kBGRA_8888_SkColorType,
3151 kOpaque_SkAlphaType);
3152
3153 // Create a new surface (that matches the backend of canvas)
3154 // to create the povDepthMap
3155 sk_sp<SkSurface> surf(this->makeSurface(info));
3156
3157 // Wrap another SPFCanvas around the surface
3158 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3159 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3160
3161 // set the depth map canvas to have the light as the user's POV
3162 depthMapCanvas->setLights(std::move(povLight));
3163
3164 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003165 povDepthMap = surf->makeImageSnapshot();
3166 }
3167
3168 // diffuseMap
3169 {
3170 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3171 picture->cullRect().height(),
3172 kBGRA_8888_SkColorType,
3173 kOpaque_SkAlphaType);
3174
3175 sk_sp<SkSurface> surf(this->makeSurface(info));
3176 surf->getCanvas()->drawPicture(picture);
3177
3178 diffuseMap = surf->makeImageSnapshot();
3179 }
vjiaoblack904527d2016-08-09 09:32:09 -07003180
3181 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3182 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003183 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3184 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003185
3186 // TODO: pass the depth to the shader in vertices, or uniforms
3187 // so we don't have to render depth and color separately
3188 for (int i = 0; i < fLights->numLights(); ++i) {
3189 // skip over ambient lights; they don't cast shadows
3190 // lights that have shadow maps do not need updating (because lights are immutable)
3191 sk_sp<SkImage> depthMap;
3192 SkISize shMapSize;
3193
3194 if (fLights->light(i).getShadowMap() != nullptr) {
3195 continue;
3196 }
3197
3198 if (fLights->light(i).isRadial()) {
3199 shMapSize.fHeight = 1;
3200 shMapSize.fWidth = (int) picture->cullRect().width();
3201
3202 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3203 kBGRA_8888_SkColorType,
3204 kOpaque_SkAlphaType);
3205
3206 // Create new surface (that matches the backend of canvas)
3207 // for each shadow map
3208 sk_sp<SkSurface> surf(this->makeSurface(info));
3209
3210 // Wrap another SPFCanvas around the surface
3211 SkCanvas* depthMapCanvas = surf->getCanvas();
3212
3213 SkLights::Builder builder;
3214 builder.add(fLights->light(i));
3215 sk_sp<SkLights> curLight = builder.finish();
3216
3217 sk_sp<SkShader> shadowMapShader;
3218 shadowMapShader = SkRadialShadowMapShader::Make(
3219 povDepthShader, curLight,
3220 (int) picture->cullRect().width(),
3221 (int) picture->cullRect().height());
3222
3223 SkPaint shadowMapPaint;
3224 shadowMapPaint.setShader(std::move(shadowMapShader));
3225
3226 depthMapCanvas->setLights(curLight);
3227
3228 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3229 diffuseMap->height()),
3230 shadowMapPaint);
3231
3232 depthMap = surf->makeImageSnapshot();
3233
3234 } else {
3235 // TODO: compute the correct size of the depth map from the light properties
3236 // TODO: maybe add a kDepth_8_SkColorType
3237 // TODO: find actual max depth of picture
3238 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3239 fLights->light(i), 255,
3240 (int) picture->cullRect().width(),
3241 (int) picture->cullRect().height());
3242
3243 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3244 kBGRA_8888_SkColorType,
3245 kOpaque_SkAlphaType);
3246
3247 // Create a new surface (that matches the backend of canvas)
3248 // for each shadow map
3249 sk_sp<SkSurface> surf(this->makeSurface(info));
3250
3251 // Wrap another SPFCanvas around the surface
3252 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3253 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3254 depthMapCanvas->setShadowParams(params);
3255
3256 // set the depth map canvas to have the light we're drawing.
3257 SkLights::Builder builder;
3258 builder.add(fLights->light(i));
3259 sk_sp<SkLights> curLight = builder.finish();
3260 depthMapCanvas->setLights(std::move(curLight));
3261
3262 depthMapCanvas->drawPicture(picture);
3263 depthMap = surf->makeImageSnapshot();
3264 }
3265
3266 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3267 fLights->light(i).setShadowMap(std::move(depthMap));
3268 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3269 // we blur the variance map
3270 SkPaint blurPaint;
3271 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3272 params.fShadowRadius, nullptr));
3273
3274 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3275 kBGRA_8888_SkColorType,
3276 kOpaque_SkAlphaType);
3277
3278 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3279
3280 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3281
3282 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3283 }
3284 }
3285
3286 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003287 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3288 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003289 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003290 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003291 diffuseMap->height(),
3292 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003293
3294 shadowPaint.setShader(shadowShader);
3295
3296 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003297}
3298#endif
3299
reed@android.com8a1c16f2008-12-17 15:59:43 +00003300///////////////////////////////////////////////////////////////////////////////
3301///////////////////////////////////////////////////////////////////////////////
3302
reed3aafe112016-08-18 12:45:34 -07003303SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003304 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003305
3306 SkASSERT(canvas);
3307
reed3aafe112016-08-18 12:45:34 -07003308 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003309 fDone = !fImpl->next();
3310}
3311
3312SkCanvas::LayerIter::~LayerIter() {
3313 fImpl->~SkDrawIter();
3314}
3315
3316void SkCanvas::LayerIter::next() {
3317 fDone = !fImpl->next();
3318}
3319
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003320SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003321 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003322}
3323
3324const SkMatrix& SkCanvas::LayerIter::matrix() const {
3325 return fImpl->getMatrix();
3326}
3327
3328const SkPaint& SkCanvas::LayerIter::paint() const {
3329 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003330 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003331 paint = &fDefaultPaint;
3332 }
3333 return *paint;
3334}
3335
reed1e7f5e72016-04-27 07:49:17 -07003336const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003337int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3338int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003339
3340///////////////////////////////////////////////////////////////////////////////
3341
fmalitac3b589a2014-06-05 12:40:07 -07003342SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003343
3344///////////////////////////////////////////////////////////////////////////////
3345
3346static bool supported_for_raster_canvas(const SkImageInfo& info) {
3347 switch (info.alphaType()) {
3348 case kPremul_SkAlphaType:
3349 case kOpaque_SkAlphaType:
3350 break;
3351 default:
3352 return false;
3353 }
3354
3355 switch (info.colorType()) {
3356 case kAlpha_8_SkColorType:
3357 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003358 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003359 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003360 break;
3361 default:
3362 return false;
3363 }
3364
3365 return true;
3366}
3367
Mike Reed5df49342016-11-12 08:06:55 -06003368std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3369 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003370 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003371 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003372 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003373
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003374 SkBitmap bitmap;
3375 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003376 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003377 }
Mike Reed5df49342016-11-12 08:06:55 -06003378 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003379}
reedd5fa1a42014-08-09 11:08:05 -07003380
3381///////////////////////////////////////////////////////////////////////////////
3382
3383SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003384 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003385 : fCanvas(canvas)
3386 , fSaveCount(canvas->getSaveCount())
3387{
bsalomon49f085d2014-09-05 13:34:00 -07003388 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003389 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003390 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003391 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003392 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003393 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003394 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003395 canvas->save();
3396 }
mtklein6cfa73a2014-08-13 13:33:49 -07003397
bsalomon49f085d2014-09-05 13:34:00 -07003398 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003399 canvas->concat(*matrix);
3400 }
3401}
3402
3403SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3404 fCanvas->restoreToCount(fSaveCount);
3405}
reede8f30622016-03-23 18:59:25 -07003406
Florin Malitaee424ac2016-12-01 12:47:59 -05003407///////////////////////////////////////////////////////////////////////////////
3408
3409SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3410 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3411
Florin Malita439ace92016-12-02 12:05:41 -05003412SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3413 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3414
Florin Malitaee424ac2016-12-01 12:47:59 -05003415SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3416 (void)this->INHERITED::getSaveLayerStrategy(rec);
3417 return kNoLayer_SaveLayerStrategy;
3418}
3419
3420///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003421
reed73603f32016-09-20 08:42:38 -07003422static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3423static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3424static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3425static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3426static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3427static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003428
3429///////////////////////////////////////////////////////////////////////////////////////////////////
3430
3431SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3432 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3433 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3434 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3435 SkIPoint origin = dev->getOrigin();
3436 SkMatrix ctm = this->getTotalMatrix();
3437 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3438
3439 SkIRect clip = fMCRec->fRasterClip.getBounds();
3440 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003441 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003442 clip.setEmpty();
3443 }
3444
3445 fAllocator->updateHandle(handle, ctm, clip);
3446 return handle;
3447 }
3448 return nullptr;
3449}
3450
3451static bool install(SkBitmap* bm, const SkImageInfo& info,
3452 const SkRasterHandleAllocator::Rec& rec) {
3453 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3454 rec.fReleaseProc, rec.fReleaseCtx);
3455}
3456
3457SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3458 SkBitmap* bm) {
3459 SkRasterHandleAllocator::Rec rec;
3460 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3461 return nullptr;
3462 }
3463 return rec.fHandle;
3464}
3465
3466std::unique_ptr<SkCanvas>
3467SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3468 const SkImageInfo& info, const Rec* rec) {
3469 if (!alloc || !supported_for_raster_canvas(info)) {
3470 return nullptr;
3471 }
3472
3473 SkBitmap bm;
3474 Handle hndl;
3475
3476 if (rec) {
3477 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3478 } else {
3479 hndl = alloc->allocBitmap(info, &bm);
3480 }
3481 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3482}