blob: 5c7039fc50e3bf050469003022b9577916ff7ffc [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;
Mike Reedc61abee2017-02-28 17:45:27 -05001151 if (filter) {
1152 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
1153 }
reeda2217ef2016-07-20 06:04:34 -07001154
Mike Reedc42a1cd2017-02-14 14:25:14 -05001155 int x = src->getOrigin().x() - dstOrigin.x();
1156 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001157 auto special = src->snapSpecial();
1158 if (special) {
1159 dst->drawSpecial(draw, special.get(), x, y, p);
1160 }
robertphillips7354a4b2015-12-16 05:08:27 -08001161}
reed70ee31b2015-12-10 13:44:45 -08001162
reed129ed1c2016-02-22 06:42:31 -08001163static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1164 const SkPaint* paint) {
1165 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1166 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001167 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001168 const bool hasImageFilter = paint && paint->getImageFilter();
1169
1170 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1171 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1172 // force to L32
1173 return SkImageInfo::MakeN32(w, h, alphaType);
1174 } else {
1175 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001176 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001177 }
1178}
1179
reed4960eee2015-12-18 07:09:18 -08001180void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1181 const SkRect* bounds = rec.fBounds;
1182 const SkPaint* paint = rec.fPaint;
1183 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1184
reed8c30a812016-04-20 16:36:51 -07001185 SkLazyPaint lazyP;
1186 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1187 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001188 SkMatrix remainder;
1189 SkSize scale;
1190 /*
1191 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1192 * but they do handle scaling. To accommodate this, we do the following:
1193 *
1194 * 1. Stash off the current CTM
1195 * 2. Decompose the CTM into SCALE and REMAINDER
1196 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1197 * contains the REMAINDER
1198 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1199 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1200 * of the original imagefilter, and draw that (via drawSprite)
1201 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1202 *
1203 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1204 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1205 */
reed96a04f32016-04-25 09:25:15 -07001206 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001207 stashedMatrix.decomposeScale(&scale, &remainder))
1208 {
1209 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1210 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1211 SkPaint* p = lazyP.set(*paint);
1212 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1213 SkFilterQuality::kLow_SkFilterQuality,
1214 sk_ref_sp(imageFilter)));
1215 imageFilter = p->getImageFilter();
1216 paint = p;
1217 }
reed8c30a812016-04-20 16:36:51 -07001218
junov@chromium.orga907ac32012-02-24 21:54:07 +00001219 // do this before we create the layer. We don't call the public save() since
1220 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001221 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001222
1223 fDeviceCMDirty = true;
1224
1225 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001226 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001227 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228 }
1229
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001230 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1231 // the clipRectBounds() call above?
1232 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001233 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001234 }
1235
reed4960eee2015-12-18 07:09:18 -08001236 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001237 SkPixelGeometry geo = fProps.pixelGeometry();
1238 if (paint) {
reed76033be2015-03-14 10:54:31 -07001239 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001240 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001241 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001242 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001243 }
1244 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245
robertphillips5139e502016-07-19 05:10:40 -07001246 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001247 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001248 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001249 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001250 }
reedb2db8982014-11-13 12:41:02 -08001251
robertphillips5139e502016-07-19 05:10:40 -07001252 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001253 paint);
1254
Hal Canary704cd322016-11-07 14:13:52 -05001255 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001256 {
reed70ee31b2015-12-10 13:44:45 -08001257 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001258 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001259 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001260 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001261 preserveLCDText,
1262 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001263 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1264 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001265 return;
reed61f501f2015-04-29 08:34:00 -07001266 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001267 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001268#ifndef SK_USE_DEVICE_CLIPPING
1269 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1270#endif
robertphillips7354a4b2015-12-16 05:08:27 -08001271
Hal Canary704cd322016-11-07 14:13:52 -05001272 DeviceCM* layer =
1273 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001274
Mike Reedb43a3e02017-02-11 10:18:58 -05001275 // only have a "next" if this new layer doesn't affect the clip (rare)
1276 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277 fMCRec->fLayer = layer;
1278 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001279
Mike Reedc61abee2017-02-28 17:45:27 -05001280 if ((rec.fSaveLayerFlags & kInitWithPrevious_SaveLayerFlag) || rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001281 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
reeda2217ef2016-07-20 06:04:34 -07001282 fMCRec->fMatrix, this->getClipStack());
1283 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001284
1285#ifdef SK_USE_DEVICE_CLIPPING
1286 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1287
1288 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1289 if (layer->fNext) {
1290 // need to punch a hole in the previous device, so we don't draw there, given that
1291 // the new top-layer will allow drawing to happen "below" it.
1292 SkRegion hole(ir);
1293 do {
1294 layer = layer->fNext;
1295 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1296 } while (layer->fNext);
1297 }
1298#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299}
1300
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001301int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001302 if (0xFF == alpha) {
1303 return this->saveLayer(bounds, nullptr);
1304 } else {
1305 SkPaint tmpPaint;
1306 tmpPaint.setAlpha(alpha);
1307 return this->saveLayer(bounds, &tmpPaint);
1308 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001309}
1310
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311void SkCanvas::internalRestore() {
1312 SkASSERT(fMCStack.count() != 0);
1313
1314 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315
reed687fa1c2015-04-07 08:00:56 -07001316 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001317
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001318 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 DeviceCM* layer = fMCRec->fLayer; // may be null
1320 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001321 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322
1323 // now do the normal restore()
1324 fMCRec->~MCRec(); // balanced in save()
1325 fMCStack.pop_back();
1326 fMCRec = (MCRec*)fMCStack.back();
1327
Mike Reedc42a1cd2017-02-14 14:25:14 -05001328#ifdef SK_USE_DEVICE_CLIPPING
1329 if (fMCRec) {
1330 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1331 }
1332#endif
1333
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1335 since if we're being recorded, we don't want to record this (the
1336 recorder will have already recorded the restore).
1337 */
bsalomon49f085d2014-09-05 13:34:00 -07001338 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001339 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001340 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001341 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001342 // restore what we smashed in internalSaveLayer
1343 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001344 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001345 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001346 delete layer;
reedb679ca82015-04-07 04:40:48 -07001347 } else {
1348 // we're at the root
reeda499f902015-05-01 09:34:31 -07001349 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001350 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001351 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001352 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001353 }
msarettfbfa2582016-08-12 08:29:08 -07001354
1355 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001356 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001357 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1358 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001359}
1360
reede8f30622016-03-23 18:59:25 -07001361sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001362 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001363 props = &fProps;
1364 }
1365 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001366}
1367
reede8f30622016-03-23 18:59:25 -07001368sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001369 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001370 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001371}
1372
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001373SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001374 return this->onImageInfo();
1375}
1376
1377SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001378 SkBaseDevice* dev = this->getDevice();
1379 if (dev) {
1380 return dev->imageInfo();
1381 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001382 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001383 }
1384}
1385
brianosman898235c2016-04-06 07:38:23 -07001386bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001387 return this->onGetProps(props);
1388}
1389
1390bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001391 SkBaseDevice* dev = this->getDevice();
1392 if (dev) {
1393 if (props) {
1394 *props = fProps;
1395 }
1396 return true;
1397 } else {
1398 return false;
1399 }
1400}
1401
reed6ceeebd2016-03-09 14:26:26 -08001402bool SkCanvas::peekPixels(SkPixmap* pmap) {
1403 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001404}
1405
reed884e97c2015-05-26 11:31:54 -07001406bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001407 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001408 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001409}
1410
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001411void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001412 SkPixmap pmap;
1413 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001414 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001415 }
1416 if (info) {
1417 *info = pmap.info();
1418 }
1419 if (rowBytes) {
1420 *rowBytes = pmap.rowBytes();
1421 }
1422 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001423 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001424 }
reed884e97c2015-05-26 11:31:54 -07001425 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001426}
1427
reed884e97c2015-05-26 11:31:54 -07001428bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001429 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001430 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001431}
1432
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001434
reed7503d602016-07-15 14:23:29 -07001435void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001437 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001438 paint = &tmp;
1439 }
reed@google.com4b226022011-01-11 18:32:13 +00001440
reed@google.com8926b162012-03-23 15:36:36 +00001441 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001442
reed@android.com8a1c16f2008-12-17 15:59:43 +00001443 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001444 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001445 paint = &looper.paint();
1446 SkImageFilter* filter = paint->getImageFilter();
1447 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001448 if (filter) {
1449 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1450 if (specialImage) {
1451 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1452 }
reed@google.com76dd2772012-01-05 21:15:07 +00001453 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001454 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001455 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001456 }
reeda2217ef2016-07-20 06:04:34 -07001457
reed@google.com4e2b3d32011-04-07 14:18:59 +00001458 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001459}
1460
reed32704672015-12-16 08:27:10 -08001461/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001462
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001463void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001464 if (dx || dy) {
1465 this->checkForDeferredSave();
1466 fDeviceCMDirty = true;
1467 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001468
reedfe69b502016-09-12 06:31:48 -07001469 // Translate shouldn't affect the is-scale-translateness of the matrix.
1470 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001471
Mike Reedc42a1cd2017-02-14 14:25:14 -05001472#ifdef SK_USE_DEVICE_CLIPPING
1473 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1474#endif
1475
reedfe69b502016-09-12 06:31:48 -07001476 this->didTranslate(dx,dy);
1477 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001478}
1479
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001480void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001481 SkMatrix m;
1482 m.setScale(sx, sy);
1483 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001484}
1485
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001486void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001487 SkMatrix m;
1488 m.setRotate(degrees);
1489 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001490}
1491
bungeman7438bfc2016-07-12 15:01:19 -07001492void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1493 SkMatrix m;
1494 m.setRotate(degrees, px, py);
1495 this->concat(m);
1496}
1497
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001498void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001499 SkMatrix m;
1500 m.setSkew(sx, sy);
1501 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001502}
1503
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001504void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001505 if (matrix.isIdentity()) {
1506 return;
1507 }
1508
reed2ff1fce2014-12-11 07:07:37 -08001509 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001510 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001511 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001512 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001513
1514#ifdef SK_USE_DEVICE_CLIPPING
1515 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1516#endif
1517
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001518 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001519}
1520
reed8c30a812016-04-20 16:36:51 -07001521void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001522 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001523 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001524 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001525
1526#ifdef SK_USE_DEVICE_CLIPPING
1527 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1528#endif
reed8c30a812016-04-20 16:36:51 -07001529}
1530
1531void SkCanvas::setMatrix(const SkMatrix& matrix) {
1532 this->checkForDeferredSave();
1533 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001534 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001535}
1536
reed@android.com8a1c16f2008-12-17 15:59:43 +00001537void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001538 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001539}
1540
vjiaoblack95302da2016-07-21 10:25:54 -07001541#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001542void SkCanvas::translateZ(SkScalar z) {
1543 this->checkForDeferredSave();
1544 this->fMCRec->fCurDrawDepth += z;
1545 this->didTranslateZ(z);
1546}
1547
1548SkScalar SkCanvas::getZ() const {
1549 return this->fMCRec->fCurDrawDepth;
1550}
1551
vjiaoblack95302da2016-07-21 10:25:54 -07001552void SkCanvas::setLights(sk_sp<SkLights> lights) {
1553 this->fLights = lights;
1554}
1555
1556sk_sp<SkLights> SkCanvas::getLights() const {
1557 return this->fLights;
1558}
1559#endif
1560
reed@android.com8a1c16f2008-12-17 15:59:43 +00001561//////////////////////////////////////////////////////////////////////////////
1562
Mike Reedc1f77742016-12-09 09:00:50 -05001563void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001564 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001565 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1566 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001567}
1568
Mike Reedc1f77742016-12-09 09:00:50 -05001569void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001570 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001571
1572#ifdef SK_USE_DEVICE_CLIPPING
1573 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
1574#endif
1575
reedc64eff52015-11-21 12:39:45 -08001576 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001577 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1578 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1579 isAA);
reedc64eff52015-11-21 12:39:45 -08001580 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001581 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001582}
1583
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001584void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1585 fClipRestrictionRect = rect;
1586 fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
Mike Reedd519d482017-02-16 11:04:52 -05001587 if (fClipRestrictionRect.isEmpty()) {
1588 // we notify the device, but we *dont* resolve deferred saves (since we're just
1589 // removing the restriction if the rect is empty. how I hate this api.
1590#ifdef SK_USE_DEVICE_CLIPPING
1591 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
1592#endif
1593 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001594 this->checkForDeferredSave();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001595#ifdef SK_USE_DEVICE_CLIPPING
Mike Reedd519d482017-02-16 11:04:52 -05001596 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001597#endif
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001598 AutoValidateClip avc(this);
1599 fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
1600 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
1601 fDeviceCMDirty = true;
1602 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1603 }
1604}
1605
Mike Reedc1f77742016-12-09 09:00:50 -05001606void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001607 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001608 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001609 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001610 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1611 } else {
1612 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001613 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001614}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001615
Mike Reedc1f77742016-12-09 09:00:50 -05001616void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001617 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001618
Brian Salomona3b45d42016-10-03 11:36:16 -04001619 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001620
Brian Salomona3b45d42016-10-03 11:36:16 -04001621 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001622
1623#ifdef SK_USE_DEVICE_CLIPPING
1624 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
1625#endif
1626
Brian Salomona3b45d42016-10-03 11:36:16 -04001627 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1628 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1629 isAA);
1630 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1631 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001632}
1633
Mike Reedc1f77742016-12-09 09:00:50 -05001634void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001635 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001636 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001637
1638 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1639 SkRect r;
1640 if (path.isRect(&r)) {
1641 this->onClipRect(r, op, edgeStyle);
1642 return;
1643 }
1644 SkRRect rrect;
1645 if (path.isOval(&r)) {
1646 rrect.setOval(r);
1647 this->onClipRRect(rrect, op, edgeStyle);
1648 return;
1649 }
1650 if (path.isRRect(&rrect)) {
1651 this->onClipRRect(rrect, op, edgeStyle);
1652 return;
1653 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001654 }
robertphillips39f05382015-11-24 09:30:12 -08001655
1656 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001657}
1658
Mike Reedc1f77742016-12-09 09:00:50 -05001659void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001660 AutoValidateClip avc(this);
1661
reed@android.com8a1c16f2008-12-17 15:59:43 +00001662 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001663 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001664
1665#ifdef SK_USE_DEVICE_CLIPPING
1666 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
1667#endif
1668
Brian Salomona3b45d42016-10-03 11:36:16 -04001669 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001670
Brian Salomona3b45d42016-10-03 11:36:16 -04001671 const SkPath* rasterClipPath = &path;
1672 const SkMatrix* matrix = &fMCRec->fMatrix;
1673 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001674 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001675 isAA = getClipStack()->asPath(&tempPath);
1676 rasterClipPath = &tempPath;
1677 matrix = &SkMatrix::I();
Mike Reedc1f77742016-12-09 09:00:50 -05001678 op = kReplace_SkClipOp;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001679 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001680 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1681 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001682 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001683}
1684
Mike Reedc1f77742016-12-09 09:00:50 -05001685void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001686 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001687 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001688}
1689
Mike Reedc1f77742016-12-09 09:00:50 -05001690void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001691#ifdef SK_USE_DEVICE_CLIPPING
1692 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
1693#endif
1694
reed@google.com5c3d1472011-02-22 19:12:23 +00001695 AutoValidateClip avc(this);
1696
reed@android.com8a1c16f2008-12-17 15:59:43 +00001697 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001698
reed@google.com5c3d1472011-02-22 19:12:23 +00001699 // todo: signal fClipStack that we have a region, and therefore (I guess)
1700 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001701 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001702
reed73603f32016-09-20 08:42:38 -07001703 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001704 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001705}
1706
reed@google.com819c9212011-02-23 18:56:55 +00001707#ifdef SK_DEBUG
1708void SkCanvas::validateClip() const {
1709 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001710 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001711 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001712 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001713 return;
1714 }
1715
reed@google.com819c9212011-02-23 18:56:55 +00001716 SkIRect ir;
1717 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001718 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001719
reed687fa1c2015-04-07 08:00:56 -07001720 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001721 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001722 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001723 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001724 case SkClipStack::Element::kRect_Type:
1725 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001726 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001727 break;
1728 case SkClipStack::Element::kEmpty_Type:
1729 tmpClip.setEmpty();
1730 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001731 default: {
1732 SkPath path;
1733 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001734 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1735 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001736 break;
1737 }
reed@google.com819c9212011-02-23 18:56:55 +00001738 }
1739 }
reed@google.com819c9212011-02-23 18:56:55 +00001740}
1741#endif
1742
reed@google.com90c07ea2012-04-13 13:50:27 +00001743void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001744 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001745 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001746
halcanary96fcdcc2015-08-27 07:41:13 -07001747 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001748 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001749 }
1750}
1751
reed@google.com5c3d1472011-02-22 19:12:23 +00001752///////////////////////////////////////////////////////////////////////////////
1753
reed@google.com754de5f2014-02-24 19:38:20 +00001754bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001755 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001756}
1757
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001758bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001759 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001760}
1761
msarettfbfa2582016-08-12 08:29:08 -07001762static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1763#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1764 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1765 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1766 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1767 return 0xF != _mm_movemask_ps(mask);
1768#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1769 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1770 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1771 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1772 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1773#else
1774 SkRect devRectAsRect;
1775 SkRect devClipAsRect;
1776 devRect.store(&devRectAsRect.fLeft);
1777 devClip.store(&devClipAsRect.fLeft);
1778 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1779#endif
1780}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001781
msarettfbfa2582016-08-12 08:29:08 -07001782// It's important for this function to not be inlined. Otherwise the compiler will share code
1783// between the fast path and the slow path, resulting in two slow paths.
1784static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1785 const SkMatrix& matrix) {
1786 SkRect deviceRect;
1787 matrix.mapRect(&deviceRect, src);
1788 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1789}
1790
1791bool SkCanvas::quickReject(const SkRect& src) const {
1792#ifdef SK_DEBUG
1793 // Verify that fDeviceClipBounds are set properly.
1794 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001795 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001796 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001797 } else {
msarettfbfa2582016-08-12 08:29:08 -07001798 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001799 }
msarettfbfa2582016-08-12 08:29:08 -07001800
msarett9637ea92016-08-18 14:03:30 -07001801 // Verify that fIsScaleTranslate is set properly.
1802 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001803#endif
1804
msarett9637ea92016-08-18 14:03:30 -07001805 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001806 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1807 }
1808
1809 // We inline the implementation of mapScaleTranslate() for the fast path.
1810 float sx = fMCRec->fMatrix.getScaleX();
1811 float sy = fMCRec->fMatrix.getScaleY();
1812 float tx = fMCRec->fMatrix.getTranslateX();
1813 float ty = fMCRec->fMatrix.getTranslateY();
1814 Sk4f scale(sx, sy, sx, sy);
1815 Sk4f trans(tx, ty, tx, ty);
1816
1817 // Apply matrix.
1818 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1819
1820 // Make sure left < right, top < bottom.
1821 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1822 Sk4f min = Sk4f::Min(ltrb, rblt);
1823 Sk4f max = Sk4f::Max(ltrb, rblt);
1824 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1825 // ARM this sequence generates the fastest (a single instruction).
1826 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1827
1828 // Check if the device rect is NaN or outside the clip.
1829 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001830}
1831
reed@google.com3b3e8952012-08-16 20:53:31 +00001832bool SkCanvas::quickReject(const SkPath& path) const {
1833 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001834}
1835
Mike Reed42e8c532017-01-23 14:09:13 -05001836SkRect SkCanvas::onGetLocalClipBounds() const {
1837 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001838 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001839 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001840 }
1841
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001842 SkMatrix inverse;
1843 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001844 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001845 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001846 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001847
Mike Reed42e8c532017-01-23 14:09:13 -05001848 SkRect bounds;
1849 SkRect r;
1850 // adjust it outwards in case we are antialiasing
1851 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001852
Mike Reed42e8c532017-01-23 14:09:13 -05001853 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1854 ibounds.fRight + inset, ibounds.fBottom + inset);
1855 inverse.mapRect(&bounds, r);
1856 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001857}
1858
Mike Reed42e8c532017-01-23 14:09:13 -05001859SkIRect SkCanvas::onGetDeviceClipBounds() const {
reed1f836ee2014-07-07 07:49:34 -07001860 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001861 if (clip.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001862 return SkIRect::MakeEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001863 }
Mike Reed42e8c532017-01-23 14:09:13 -05001864 return clip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001865}
1866
reed@android.com8a1c16f2008-12-17 15:59:43 +00001867const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001868 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001869}
1870
Mike Reed3726a4a2017-01-19 11:36:41 -05001871void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1872 // we know that ganesh doesn't track the rgn, so ask for its clipstack
1873 if (this->getGrContext()) {
Stan Iliev4eabd5d2017-02-21 11:15:53 -05001874 const SkClipStack* cs = this->getClipStack();
1875 SkClipStack::BoundsType boundType;
1876 bool isIntersectionOfRects;
1877 SkRect bounds;
1878 cs->getBounds(&bounds, &boundType, &isIntersectionOfRects);
1879 if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
1880 rgn->setRect(bounds.round());
1881 return;
1882 }
Mike Reed3726a4a2017-01-19 11:36:41 -05001883 SkPath path;
Stan Iliev4eabd5d2017-02-21 11:15:53 -05001884 cs->asPath(&path);
Mike Reed3726a4a2017-01-19 11:36:41 -05001885 SkISize size = this->getBaseLayerSize();
1886 rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
1887 } else {
1888 *rgn = fMCRec->fRasterClip.forceGetBW();
1889 }
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001890}
1891
Brian Osman11052242016-10-27 14:47:55 -04001892GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001893 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001894 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001895}
1896
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001897GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001898 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001899 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001900}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001901
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001902void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1903 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001904 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001905 if (outer.isEmpty()) {
1906 return;
1907 }
1908 if (inner.isEmpty()) {
1909 this->drawRRect(outer, paint);
1910 return;
1911 }
1912
1913 // We don't have this method (yet), but technically this is what we should
1914 // be able to assert...
1915 // SkASSERT(outer.contains(inner));
1916 //
1917 // For now at least check for containment of bounds
1918 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1919
1920 this->onDrawDRRect(outer, inner, paint);
1921}
1922
reed41af9662015-01-05 07:49:08 -08001923// These need to stop being virtual -- clients need to override the onDraw... versions
1924
1925void SkCanvas::drawPaint(const SkPaint& paint) {
1926 this->onDrawPaint(paint);
1927}
1928
1929void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1930 this->onDrawRect(r, paint);
1931}
1932
msarettdca352e2016-08-26 06:37:45 -07001933void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1934 if (region.isEmpty()) {
1935 return;
1936 }
1937
1938 if (region.isRect()) {
1939 return this->drawIRect(region.getBounds(), paint);
1940 }
1941
1942 this->onDrawRegion(region, paint);
1943}
1944
reed41af9662015-01-05 07:49:08 -08001945void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1946 this->onDrawOval(r, paint);
1947}
1948
1949void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1950 this->onDrawRRect(rrect, paint);
1951}
1952
1953void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1954 this->onDrawPoints(mode, count, pts, paint);
1955}
1956
1957void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001958 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001959 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001960 this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices,
1961 indexCount, paint);
1962}
1963
1964void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint,
1965 uint32_t flags) {
1966 RETURN_ON_NULL(vertices);
1967 this->onDrawVerticesObject(std::move(vertices), mode, paint, flags);
reed41af9662015-01-05 07:49:08 -08001968}
1969
1970void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1971 this->onDrawPath(path, paint);
1972}
1973
reeda85d4d02015-05-06 12:56:48 -07001974void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001975 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001976 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001977}
1978
reede47829b2015-08-06 10:02:53 -07001979void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1980 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001981 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001982 if (dst.isEmpty() || src.isEmpty()) {
1983 return;
1984 }
1985 this->onDrawImageRect(image, &src, dst, paint, constraint);
1986}
reed41af9662015-01-05 07:49:08 -08001987
reed84984ef2015-07-17 07:09:43 -07001988void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1989 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001990 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001991 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001992}
1993
reede47829b2015-08-06 10:02:53 -07001994void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1995 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001996 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001997 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1998 constraint);
1999}
reede47829b2015-08-06 10:02:53 -07002000
reed4c21dc52015-06-25 12:32:03 -07002001void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2002 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002003 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07002004 if (dst.isEmpty()) {
2005 return;
2006 }
msarett552bca92016-08-03 06:53:26 -07002007 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
2008 this->onDrawImageNine(image, center, dst, paint);
2009 } else {
reede47829b2015-08-06 10:02:53 -07002010 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002011 }
reed4c21dc52015-06-25 12:32:03 -07002012}
2013
msarett16882062016-08-16 09:31:08 -07002014void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2015 const SkPaint* paint) {
2016 RETURN_ON_NULL(image);
2017 if (dst.isEmpty()) {
2018 return;
2019 }
msarett71df2d72016-09-30 12:41:42 -07002020
2021 SkIRect bounds;
2022 Lattice latticePlusBounds = lattice;
2023 if (!latticePlusBounds.fBounds) {
2024 bounds = SkIRect::MakeWH(image->width(), image->height());
2025 latticePlusBounds.fBounds = &bounds;
2026 }
2027
2028 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
2029 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07002030 } else {
2031 this->drawImageRect(image, dst, paint);
2032 }
2033}
2034
reed41af9662015-01-05 07:49:08 -08002035void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002036 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002037 return;
2038 }
reed41af9662015-01-05 07:49:08 -08002039 this->onDrawBitmap(bitmap, dx, dy, paint);
2040}
2041
reede47829b2015-08-06 10:02:53 -07002042void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002043 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002044 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002045 return;
2046 }
reede47829b2015-08-06 10:02:53 -07002047 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002048}
2049
reed84984ef2015-07-17 07:09:43 -07002050void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2051 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002052 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002053}
2054
reede47829b2015-08-06 10:02:53 -07002055void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2056 SrcRectConstraint constraint) {
2057 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2058 constraint);
2059}
reede47829b2015-08-06 10:02:53 -07002060
reed41af9662015-01-05 07:49:08 -08002061void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2062 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002063 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002064 return;
2065 }
msarett552bca92016-08-03 06:53:26 -07002066 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2067 this->onDrawBitmapNine(bitmap, center, dst, paint);
2068 } else {
reeda5517e22015-07-14 10:54:12 -07002069 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002070 }
reed41af9662015-01-05 07:49:08 -08002071}
2072
msarettc573a402016-08-02 08:05:56 -07002073void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2074 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002075 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002076 return;
2077 }
msarett71df2d72016-09-30 12:41:42 -07002078
2079 SkIRect bounds;
2080 Lattice latticePlusBounds = lattice;
2081 if (!latticePlusBounds.fBounds) {
2082 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2083 latticePlusBounds.fBounds = &bounds;
2084 }
2085
2086 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2087 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002088 } else {
msarett16882062016-08-16 09:31:08 -07002089 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002090 }
msarettc573a402016-08-02 08:05:56 -07002091}
2092
reed71c3c762015-06-24 10:29:17 -07002093void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002094 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002095 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002096 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002097 if (count <= 0) {
2098 return;
2099 }
Joe Gregorioc4859072017-01-20 14:21:27 +00002100 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002101 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002102 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002103}
2104
reedf70b5312016-03-04 16:36:20 -08002105void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2106 if (key) {
2107 this->onDrawAnnotation(rect, key, value);
2108 }
2109}
2110
reede47829b2015-08-06 10:02:53 -07002111void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2112 const SkPaint* paint, SrcRectConstraint constraint) {
2113 if (src) {
2114 this->drawImageRect(image, *src, dst, paint, constraint);
2115 } else {
2116 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2117 dst, paint, constraint);
2118 }
2119}
2120void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2121 const SkPaint* paint, SrcRectConstraint constraint) {
2122 if (src) {
2123 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2124 } else {
2125 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2126 dst, paint, constraint);
2127 }
2128}
2129
tomhudsoncb3bd182016-05-18 07:24:16 -07002130void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2131 SkIRect layer_bounds = this->getTopLayerBounds();
2132 if (matrix) {
2133 *matrix = this->getTotalMatrix();
2134 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2135 }
2136 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05002137 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07002138 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2139 }
2140}
2141
reed@android.com8a1c16f2008-12-17 15:59:43 +00002142//////////////////////////////////////////////////////////////////////////////
2143// These are the virtual drawing methods
2144//////////////////////////////////////////////////////////////////////////////
2145
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002146void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002147 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002148 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2149 }
2150}
2151
reed41af9662015-01-05 07:49:08 -08002152void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002153 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002154 this->internalDrawPaint(paint);
2155}
2156
2157void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002158 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002159
2160 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002161 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002162 }
2163
reed@google.com4e2b3d32011-04-07 14:18:59 +00002164 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002165}
2166
reed41af9662015-01-05 07:49:08 -08002167void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2168 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002169 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002170 if ((long)count <= 0) {
2171 return;
2172 }
2173
Mike Reed822128b2017-02-28 16:41:03 -05002174 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002175 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002176 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002177 // special-case 2 points (common for drawing a single line)
2178 if (2 == count) {
2179 r.set(pts[0], pts[1]);
2180 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002181 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002182 }
Mike Reed822128b2017-02-28 16:41:03 -05002183 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002184 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2185 return;
2186 }
2187 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002188 }
reed@google.coma584aed2012-05-16 14:06:02 +00002189
halcanary96fcdcc2015-08-27 07:41:13 -07002190 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002191
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002192 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002193
reed@android.com8a1c16f2008-12-17 15:59:43 +00002194 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002195 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002196 }
reed@google.com4b226022011-01-11 18:32:13 +00002197
reed@google.com4e2b3d32011-04-07 14:18:59 +00002198 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002199}
2200
reed4a167172016-08-18 17:15:25 -07002201static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2202 return ((intptr_t)paint.getImageFilter() |
2203#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2204 (intptr_t)canvas->getDrawFilter() |
2205#endif
2206 (intptr_t)paint.getLooper() ) != 0;
2207}
2208
reed41af9662015-01-05 07:49:08 -08002209void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002210 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002211 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002212 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2213 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2214 SkRect tmp(r);
2215 tmp.sort();
2216
Mike Reed822128b2017-02-28 16:41:03 -05002217 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002218 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2219 return;
2220 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002221 }
reed@google.com4b226022011-01-11 18:32:13 +00002222
reed4a167172016-08-18 17:15:25 -07002223 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002224 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002225
reed4a167172016-08-18 17:15:25 -07002226 while (iter.next()) {
2227 iter.fDevice->drawRect(iter, r, looper.paint());
2228 }
2229
2230 LOOPER_END
2231 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002232 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002233 SkDrawIter iter(this);
2234 while (iter.next()) {
2235 iter.fDevice->drawRect(iter, r, paint);
2236 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002237 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002238}
2239
msarett44df6512016-08-25 13:54:30 -07002240void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002241 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002242 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002243 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002244 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2245 return;
2246 }
msarett44df6512016-08-25 13:54:30 -07002247 }
2248
Mike Reed822128b2017-02-28 16:41:03 -05002249 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002250
2251 while (iter.next()) {
2252 iter.fDevice->drawRegion(iter, region, looper.paint());
2253 }
2254
2255 LOOPER_END
2256}
2257
reed41af9662015-01-05 07:49:08 -08002258void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002259 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002260 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002261 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002262 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2263 return;
2264 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002265 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002266
Mike Reed822128b2017-02-28 16:41:03 -05002267 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002268
2269 while (iter.next()) {
2270 iter.fDevice->drawOval(iter, oval, looper.paint());
2271 }
2272
2273 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002274}
2275
bsalomonac3aa242016-08-19 11:25:19 -07002276void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2277 SkScalar sweepAngle, bool useCenter,
2278 const SkPaint& paint) {
2279 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002280 if (paint.canComputeFastBounds()) {
2281 SkRect storage;
2282 // Note we're using the entire oval as the bounds.
2283 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2284 return;
2285 }
bsalomonac3aa242016-08-19 11:25:19 -07002286 }
2287
Mike Reed822128b2017-02-28 16:41:03 -05002288 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002289
2290 while (iter.next()) {
2291 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2292 }
2293
2294 LOOPER_END
2295}
2296
reed41af9662015-01-05 07:49:08 -08002297void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002298 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002299 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002300 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002301 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2302 return;
2303 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002304 }
2305
2306 if (rrect.isRect()) {
2307 // call the non-virtual version
2308 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002309 return;
2310 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002311 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002312 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2313 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002314 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002315
Mike Reed822128b2017-02-28 16:41:03 -05002316 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002317
2318 while (iter.next()) {
2319 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2320 }
2321
2322 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002323}
2324
Mike Reed822128b2017-02-28 16:41:03 -05002325void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002326 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002327 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002328 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2329 return;
2330 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002331 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002332
Mike Reed822128b2017-02-28 16:41:03 -05002333 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002334
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002335 while (iter.next()) {
2336 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2337 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002338
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002339 LOOPER_END
2340}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002341
reed41af9662015-01-05 07:49:08 -08002342void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002343 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002344 if (!path.isFinite()) {
2345 return;
2346 }
2347
Mike Reed822128b2017-02-28 16:41:03 -05002348 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002349 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002350 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002351 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2352 return;
2353 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002354 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002355
Mike Reed822128b2017-02-28 16:41:03 -05002356 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002357 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002358 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002359 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002360 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002361 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002362
Mike Reed822128b2017-02-28 16:41:03 -05002363 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002364
2365 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002366 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002367 }
2368
reed@google.com4e2b3d32011-04-07 14:18:59 +00002369 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002370}
2371
reed262a71b2015-12-05 13:07:27 -08002372bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002373 if (!paint.getImageFilter()) {
2374 return false;
2375 }
2376
2377 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002378 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002379 return false;
2380 }
2381
2382 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2383 // Once we can filter and the filter will return a result larger than itself, we should be
2384 // able to remove this constraint.
2385 // skbug.com/4526
2386 //
2387 SkPoint pt;
2388 ctm.mapXY(x, y, &pt);
2389 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2390 return ir.contains(fMCRec->fRasterClip.getBounds());
2391}
2392
reeda85d4d02015-05-06 12:56:48 -07002393void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002394 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002395 SkRect bounds = SkRect::MakeXYWH(x, y,
2396 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002397 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002398 SkRect tmp = bounds;
2399 if (paint) {
2400 paint->computeFastBounds(tmp, &tmp);
2401 }
2402 if (this->quickReject(tmp)) {
2403 return;
2404 }
reeda85d4d02015-05-06 12:56:48 -07002405 }
halcanary9d524f22016-03-29 09:03:52 -07002406
reeda85d4d02015-05-06 12:56:48 -07002407 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002408 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002409 paint = lazy.init();
2410 }
reed262a71b2015-12-05 13:07:27 -08002411
reeda2217ef2016-07-20 06:04:34 -07002412 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002413 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2414 *paint);
2415 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002416 special = this->getDevice()->makeSpecial(image);
2417 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002418 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002419 }
2420 }
2421
reed262a71b2015-12-05 13:07:27 -08002422 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2423
reeda85d4d02015-05-06 12:56:48 -07002424 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002425 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002426 if (special) {
2427 SkPoint pt;
2428 iter.fMatrix->mapXY(x, y, &pt);
2429 iter.fDevice->drawSpecial(iter, special.get(),
2430 SkScalarRoundToInt(pt.fX),
2431 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002432 } else {
2433 iter.fDevice->drawImage(iter, image, x, y, pnt);
2434 }
reeda85d4d02015-05-06 12:56:48 -07002435 }
halcanary9d524f22016-03-29 09:03:52 -07002436
reeda85d4d02015-05-06 12:56:48 -07002437 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002438}
2439
reed41af9662015-01-05 07:49:08 -08002440void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002441 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002442 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002443 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002444 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002445 if (paint) {
2446 paint->computeFastBounds(dst, &storage);
2447 }
2448 if (this->quickReject(storage)) {
2449 return;
2450 }
reeda85d4d02015-05-06 12:56:48 -07002451 }
2452 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002453 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002454 paint = lazy.init();
2455 }
halcanary9d524f22016-03-29 09:03:52 -07002456
senorblancoc41e7e12015-12-07 12:51:30 -08002457 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002458 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002459
reeda85d4d02015-05-06 12:56:48 -07002460 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002461 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002462 }
halcanary9d524f22016-03-29 09:03:52 -07002463
reeda85d4d02015-05-06 12:56:48 -07002464 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002465}
2466
reed41af9662015-01-05 07:49:08 -08002467void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002468 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002469 SkDEBUGCODE(bitmap.validate();)
2470
reed33366972015-10-08 09:22:02 -07002471 if (bitmap.drawsNothing()) {
2472 return;
2473 }
2474
2475 SkLazyPaint lazy;
2476 if (nullptr == paint) {
2477 paint = lazy.init();
2478 }
2479
Mike Reed822128b2017-02-28 16:41:03 -05002480 SkRect bounds;
2481 bitmap.getBounds(&bounds);
2482 bounds.offset(x, y);
2483 bool canFastBounds = paint->canComputeFastBounds();
2484 if (canFastBounds) {
2485 SkRect storage;
2486 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002487 return;
2488 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002489 }
reed@google.com4b226022011-01-11 18:32:13 +00002490
reeda2217ef2016-07-20 06:04:34 -07002491 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002492 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2493 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002494 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002495 special = this->getDevice()->makeSpecial(bitmap);
2496 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002497 drawAsSprite = false;
2498 }
2499 }
2500
Mike Reed822128b2017-02-28 16:41:03 -05002501 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2502
2503 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002504
2505 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002506 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002507 if (special) {
reed262a71b2015-12-05 13:07:27 -08002508 SkPoint pt;
2509 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002510 iter.fDevice->drawSpecial(iter, special.get(),
2511 SkScalarRoundToInt(pt.fX),
2512 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002513 } else {
2514 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2515 }
reed33366972015-10-08 09:22:02 -07002516 }
msarettfbfa2582016-08-12 08:29:08 -07002517
reed33366972015-10-08 09:22:02 -07002518 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002519}
2520
reed@google.com9987ec32011-09-07 11:57:52 +00002521// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002522void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002523 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002524 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002525 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002526 return;
2527 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002528
halcanary96fcdcc2015-08-27 07:41:13 -07002529 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002530 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002531 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2532 return;
2533 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002534 }
reed@google.com3d608122011-11-21 15:16:16 +00002535
reed@google.com33535f32012-09-25 15:37:50 +00002536 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002537 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002538 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002539 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002540
senorblancoc41e7e12015-12-07 12:51:30 -08002541 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002542 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002543
reed@google.com33535f32012-09-25 15:37:50 +00002544 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002545 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002546 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002547
reed@google.com33535f32012-09-25 15:37:50 +00002548 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002549}
2550
reed41af9662015-01-05 07:49:08 -08002551void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002552 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002553 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002554 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002555 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002556}
2557
reed4c21dc52015-06-25 12:32:03 -07002558void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2559 const SkPaint* paint) {
2560 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002561
halcanary96fcdcc2015-08-27 07:41:13 -07002562 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002563 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002564 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2565 return;
2566 }
reed@google.com3d608122011-11-21 15:16:16 +00002567 }
halcanary9d524f22016-03-29 09:03:52 -07002568
reed4c21dc52015-06-25 12:32:03 -07002569 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002570 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002571 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002572 }
halcanary9d524f22016-03-29 09:03:52 -07002573
senorblancoc41e7e12015-12-07 12:51:30 -08002574 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002575
reed4c21dc52015-06-25 12:32:03 -07002576 while (iter.next()) {
2577 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002578 }
halcanary9d524f22016-03-29 09:03:52 -07002579
reed4c21dc52015-06-25 12:32:03 -07002580 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002581}
2582
reed41af9662015-01-05 07:49:08 -08002583void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2584 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002585 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002586 SkDEBUGCODE(bitmap.validate();)
2587
halcanary96fcdcc2015-08-27 07:41:13 -07002588 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002589 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002590 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2591 return;
2592 }
reed4c21dc52015-06-25 12:32:03 -07002593 }
halcanary9d524f22016-03-29 09:03:52 -07002594
reed4c21dc52015-06-25 12:32:03 -07002595 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002596 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002597 paint = lazy.init();
2598 }
halcanary9d524f22016-03-29 09:03:52 -07002599
senorblancoc41e7e12015-12-07 12:51:30 -08002600 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002601
reed4c21dc52015-06-25 12:32:03 -07002602 while (iter.next()) {
2603 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2604 }
halcanary9d524f22016-03-29 09:03:52 -07002605
reed4c21dc52015-06-25 12:32:03 -07002606 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002607}
2608
msarett16882062016-08-16 09:31:08 -07002609void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2610 const SkPaint* paint) {
2611 if (nullptr == paint || paint->canComputeFastBounds()) {
2612 SkRect storage;
2613 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2614 return;
2615 }
2616 }
2617
2618 SkLazyPaint lazy;
2619 if (nullptr == paint) {
2620 paint = lazy.init();
2621 }
2622
2623 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2624
2625 while (iter.next()) {
2626 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2627 }
2628
2629 LOOPER_END
2630}
2631
2632void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2633 const SkRect& dst, const SkPaint* paint) {
2634 if (nullptr == paint || paint->canComputeFastBounds()) {
2635 SkRect storage;
2636 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2637 return;
2638 }
2639 }
2640
2641 SkLazyPaint lazy;
2642 if (nullptr == paint) {
2643 paint = lazy.init();
2644 }
2645
2646 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2647
2648 while (iter.next()) {
2649 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2650 }
2651
2652 LOOPER_END
2653}
2654
reed@google.comf67e4cf2011-03-15 20:56:58 +00002655class SkDeviceFilteredPaint {
2656public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002657 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002658 uint32_t filteredFlags = device->filterTextFlags(paint);
2659 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002660 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002661 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002662 fPaint = newPaint;
2663 } else {
2664 fPaint = &paint;
2665 }
2666 }
2667
reed@google.comf67e4cf2011-03-15 20:56:58 +00002668 const SkPaint& paint() const { return *fPaint; }
2669
2670private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002671 const SkPaint* fPaint;
2672 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002673};
2674
reed@google.come0d9ce82014-04-23 04:00:17 +00002675void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2676 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002677 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002678
2679 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002680 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002681 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002682 }
2683
reed@google.com4e2b3d32011-04-07 14:18:59 +00002684 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002685}
2686
reed@google.come0d9ce82014-04-23 04:00:17 +00002687void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2688 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002689 SkPoint textOffset = SkPoint::Make(0, 0);
2690
halcanary96fcdcc2015-08-27 07:41:13 -07002691 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002692
reed@android.com8a1c16f2008-12-17 15:59:43 +00002693 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002694 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002695 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002696 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002698
reed@google.com4e2b3d32011-04-07 14:18:59 +00002699 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002700}
2701
reed@google.come0d9ce82014-04-23 04:00:17 +00002702void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2703 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002704
2705 SkPoint textOffset = SkPoint::Make(0, constY);
2706
halcanary96fcdcc2015-08-27 07:41:13 -07002707 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002708
reed@android.com8a1c16f2008-12-17 15:59:43 +00002709 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002710 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002711 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002712 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002713 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002714
reed@google.com4e2b3d32011-04-07 14:18:59 +00002715 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002716}
2717
reed@google.come0d9ce82014-04-23 04:00:17 +00002718void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2719 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002720 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002721
reed@android.com8a1c16f2008-12-17 15:59:43 +00002722 while (iter.next()) {
2723 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002724 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002725 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002726
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002727 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002728}
2729
reed45561a02016-07-07 12:47:17 -07002730void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2731 const SkRect* cullRect, const SkPaint& paint) {
2732 if (cullRect && this->quickReject(*cullRect)) {
2733 return;
2734 }
2735
2736 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2737
2738 while (iter.next()) {
2739 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2740 }
2741
2742 LOOPER_END
2743}
2744
fmalita00d5c2c2014-08-21 08:53:26 -07002745void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2746 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002747
fmalita85d5eb92015-03-04 11:20:12 -08002748 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002749 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002750 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002751 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002752 SkRect tmp;
2753 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2754 return;
2755 }
2756 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002757 }
2758
fmalita024f9962015-03-03 19:08:17 -08002759 // We cannot filter in the looper as we normally do, because the paint is
2760 // incomplete at this point (text-related attributes are embedded within blob run paints).
2761 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002762 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002763
fmalita85d5eb92015-03-04 11:20:12 -08002764 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002765
fmalitaaa1b9122014-08-28 14:32:24 -07002766 while (iter.next()) {
2767 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002768 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002769 }
2770
fmalitaaa1b9122014-08-28 14:32:24 -07002771 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002772
2773 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002774}
2775
reed@google.come0d9ce82014-04-23 04:00:17 +00002776// These will become non-virtual, so they always call the (virtual) onDraw... method
2777void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2778 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002779 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002780 if (byteLength) {
2781 this->onDrawText(text, byteLength, x, y, paint);
2782 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002783}
2784void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2785 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002786 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002787 if (byteLength) {
2788 this->onDrawPosText(text, byteLength, pos, paint);
2789 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002790}
2791void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2792 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002793 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002794 if (byteLength) {
2795 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2796 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002797}
2798void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2799 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002800 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002801 if (byteLength) {
2802 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2803 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002804}
reed45561a02016-07-07 12:47:17 -07002805void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2806 const SkRect* cullRect, const SkPaint& paint) {
2807 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2808 if (byteLength) {
2809 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2810 }
2811}
fmalita00d5c2c2014-08-21 08:53:26 -07002812void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2813 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002814 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002815 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002816 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002817}
reed@google.come0d9ce82014-04-23 04:00:17 +00002818
reed41af9662015-01-05 07:49:08 -08002819void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2820 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002821 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002822 const uint16_t indices[], int indexCount,
2823 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002824 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002825 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002826
reed@android.com8a1c16f2008-12-17 15:59:43 +00002827 while (iter.next()) {
2828 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002829 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002830 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002831 }
reed@google.com4b226022011-01-11 18:32:13 +00002832
reed@google.com4e2b3d32011-04-07 14:18:59 +00002833 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002834}
2835
Brian Salomon199fb872017-02-06 09:41:10 -05002836void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode,
2837 const SkPaint& paint, uint32_t flags) {
2838 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2839 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2840
2841 while (iter.next()) {
2842 // In the common case of one iteration we could std::move vertices here.
2843 iter.fDevice->drawVerticesObject(iter, vertices, bmode, looper.paint(), flags);
2844 }
2845
2846 LOOPER_END
2847}
2848
2849void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode,
2850 const SkPaint& paint, uint32_t flags) {
2851 const SkPoint* texs =
2852 (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords();
2853 const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors();
2854 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs,
2855 colors, mode, vertices->indices(), vertices->indexCount(), paint);
2856}
2857
dandovb3c9d1c2014-08-12 08:34:29 -07002858void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002859 const SkPoint texCoords[4], SkBlendMode bmode,
2860 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002861 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002862 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002863 return;
2864 }
mtklein6cfa73a2014-08-13 13:33:49 -07002865
Mike Reedfaba3712016-11-03 14:45:31 -04002866 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002867}
2868
2869void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002870 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002871 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002872 // Since a patch is always within the convex hull of the control points, we discard it when its
2873 // bounding rectangle is completely outside the current clip.
2874 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002875 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002876 if (this->quickReject(bounds)) {
2877 return;
2878 }
mtklein6cfa73a2014-08-13 13:33:49 -07002879
halcanary96fcdcc2015-08-27 07:41:13 -07002880 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002881
dandovecfff212014-08-04 10:02:00 -07002882 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002883 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002884 }
mtklein6cfa73a2014-08-13 13:33:49 -07002885
dandovecfff212014-08-04 10:02:00 -07002886 LOOPER_END
2887}
2888
reeda8db7282015-07-07 10:22:31 -07002889void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002890 RETURN_ON_NULL(dr);
2891 if (x || y) {
2892 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2893 this->onDrawDrawable(dr, &matrix);
2894 } else {
2895 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002896 }
2897}
2898
reeda8db7282015-07-07 10:22:31 -07002899void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002900 RETURN_ON_NULL(dr);
2901 if (matrix && matrix->isIdentity()) {
2902 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002903 }
reede3b38ce2016-01-08 09:18:44 -08002904 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002905}
2906
2907void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002908 // drawable bounds are no longer reliable (e.g. android displaylist)
2909 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002910 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002911}
2912
reed71c3c762015-06-24 10:29:17 -07002913void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002914 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002915 const SkRect* cull, const SkPaint* paint) {
2916 if (cull && this->quickReject(*cull)) {
2917 return;
2918 }
2919
2920 SkPaint pnt;
2921 if (paint) {
2922 pnt = *paint;
2923 }
halcanary9d524f22016-03-29 09:03:52 -07002924
halcanary96fcdcc2015-08-27 07:41:13 -07002925 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002926 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002927 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002928 }
2929 LOOPER_END
2930}
2931
reedf70b5312016-03-04 16:36:20 -08002932void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2933 SkASSERT(key);
2934
2935 SkPaint paint;
2936 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2937 while (iter.next()) {
2938 iter.fDevice->drawAnnotation(iter, rect, key, value);
2939 }
2940 LOOPER_END
2941}
2942
reed@android.com8a1c16f2008-12-17 15:59:43 +00002943//////////////////////////////////////////////////////////////////////////////
2944// These methods are NOT virtual, and therefore must call back into virtual
2945// methods, rather than actually drawing themselves.
2946//////////////////////////////////////////////////////////////////////////////
2947
Mike Reed3661bc92017-02-22 13:21:42 -05002948#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed374772b2016-10-05 17:33:02 -07002949void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002950 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002951 SkPaint paint;
2952
2953 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002954 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002955 this->drawPaint(paint);
2956}
Mike Reed3661bc92017-02-22 13:21:42 -05002957#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002958
reed374772b2016-10-05 17:33:02 -07002959void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002960 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002961 SkPaint paint;
2962
2963 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002964 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002965 this->drawPaint(paint);
2966}
2967
2968void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002969 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002970 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002971 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2972}
2973
Mike Reed3661bc92017-02-22 13:21:42 -05002974#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002975void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002976 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002977 SkPoint pt;
2978 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002979
reed@android.com8a1c16f2008-12-17 15:59:43 +00002980 pt.set(x, y);
2981 paint.setColor(color);
2982 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2983}
Mike Reed3661bc92017-02-22 13:21:42 -05002984#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002985
Mike Reed3661bc92017-02-22 13:21:42 -05002986void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002987 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002988 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002989
reed@android.com8a1c16f2008-12-17 15:59:43 +00002990 pts[0].set(x0, y0);
2991 pts[1].set(x1, y1);
2992 this->drawPoints(kLines_PointMode, 2, pts, paint);
2993}
2994
Mike Reed3661bc92017-02-22 13:21:42 -05002995#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002996void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2997 SkScalar right, SkScalar bottom,
2998 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002999 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003000 SkRect r;
3001
3002 r.set(left, top, right, bottom);
3003 this->drawRect(r, paint);
3004}
Mike Reed3661bc92017-02-22 13:21:42 -05003005#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00003006
Mike Reed3661bc92017-02-22 13:21:42 -05003007void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003008 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003009 if (radius < 0) {
3010 radius = 0;
3011 }
3012
3013 SkRect r;
3014 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003015 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003016}
3017
3018void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3019 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003020 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003021 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003022 SkRRect rrect;
3023 rrect.setRectXY(r, rx, ry);
3024 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003025 } else {
3026 this->drawRect(r, paint);
3027 }
3028}
3029
reed@android.com8a1c16f2008-12-17 15:59:43 +00003030void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3031 SkScalar sweepAngle, bool useCenter,
3032 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003033 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003034 if (oval.isEmpty() || !sweepAngle) {
3035 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003036 }
bsalomon21af9ca2016-08-25 12:29:23 -07003037 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003038}
3039
3040void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3041 const SkPath& path, SkScalar hOffset,
3042 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003043 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003044 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003045
reed@android.com8a1c16f2008-12-17 15:59:43 +00003046 matrix.setTranslate(hOffset, vOffset);
3047 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3048}
3049
reed@android.comf76bacf2009-05-13 14:00:33 +00003050///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003051
3052/**
3053 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3054 * against the playback cost of recursing into the subpicture to get at its actual ops.
3055 *
3056 * For now we pick a conservatively small value, though measurement (and other heuristics like
3057 * the type of ops contained) may justify changing this value.
3058 */
3059#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003060
reedd5fa1a42014-08-09 11:08:05 -07003061void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003062 RETURN_ON_NULL(picture);
3063
reed1c2c4412015-04-30 13:09:24 -07003064 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003065 if (matrix && matrix->isIdentity()) {
3066 matrix = nullptr;
3067 }
3068 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3069 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3070 picture->playback(this);
3071 } else {
3072 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003073 }
3074}
robertphillips9b14f262014-06-04 05:40:44 -07003075
reedd5fa1a42014-08-09 11:08:05 -07003076void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3077 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003078 if (!paint || paint->canComputeFastBounds()) {
3079 SkRect bounds = picture->cullRect();
3080 if (paint) {
3081 paint->computeFastBounds(bounds, &bounds);
3082 }
3083 if (matrix) {
3084 matrix->mapRect(&bounds);
3085 }
3086 if (this->quickReject(bounds)) {
3087 return;
3088 }
3089 }
3090
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003091 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003092 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003093}
3094
vjiaoblack95302da2016-07-21 10:25:54 -07003095#ifdef SK_EXPERIMENTAL_SHADOWING
3096void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3097 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003098 const SkPaint* paint,
3099 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003100 RETURN_ON_NULL(picture);
3101
3102 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3103
vjiaoblacke6f5d562016-08-25 06:30:23 -07003104 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003105}
3106
3107void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3108 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003109 const SkPaint* paint,
3110 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003111 if (!paint || paint->canComputeFastBounds()) {
3112 SkRect bounds = picture->cullRect();
3113 if (paint) {
3114 paint->computeFastBounds(bounds, &bounds);
3115 }
3116 if (matrix) {
3117 matrix->mapRect(&bounds);
3118 }
3119 if (this->quickReject(bounds)) {
3120 return;
3121 }
3122 }
3123
3124 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3125
vjiaoblacke6f5d562016-08-25 06:30:23 -07003126 sk_sp<SkImage> povDepthMap;
3127 sk_sp<SkImage> diffuseMap;
3128
vjiaoblack904527d2016-08-09 09:32:09 -07003129 // povDepthMap
3130 {
3131 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003132 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3133 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003134 sk_sp<SkLights> povLight = builder.finish();
3135
3136 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3137 picture->cullRect().height(),
3138 kBGRA_8888_SkColorType,
3139 kOpaque_SkAlphaType);
3140
3141 // Create a new surface (that matches the backend of canvas)
3142 // to create the povDepthMap
3143 sk_sp<SkSurface> surf(this->makeSurface(info));
3144
3145 // Wrap another SPFCanvas around the surface
3146 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3147 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3148
3149 // set the depth map canvas to have the light as the user's POV
3150 depthMapCanvas->setLights(std::move(povLight));
3151
3152 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003153 povDepthMap = surf->makeImageSnapshot();
3154 }
3155
3156 // diffuseMap
3157 {
3158 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3159 picture->cullRect().height(),
3160 kBGRA_8888_SkColorType,
3161 kOpaque_SkAlphaType);
3162
3163 sk_sp<SkSurface> surf(this->makeSurface(info));
3164 surf->getCanvas()->drawPicture(picture);
3165
3166 diffuseMap = surf->makeImageSnapshot();
3167 }
vjiaoblack904527d2016-08-09 09:32:09 -07003168
3169 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3170 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003171 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3172 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003173
3174 // TODO: pass the depth to the shader in vertices, or uniforms
3175 // so we don't have to render depth and color separately
3176 for (int i = 0; i < fLights->numLights(); ++i) {
3177 // skip over ambient lights; they don't cast shadows
3178 // lights that have shadow maps do not need updating (because lights are immutable)
3179 sk_sp<SkImage> depthMap;
3180 SkISize shMapSize;
3181
3182 if (fLights->light(i).getShadowMap() != nullptr) {
3183 continue;
3184 }
3185
3186 if (fLights->light(i).isRadial()) {
3187 shMapSize.fHeight = 1;
3188 shMapSize.fWidth = (int) picture->cullRect().width();
3189
3190 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3191 kBGRA_8888_SkColorType,
3192 kOpaque_SkAlphaType);
3193
3194 // Create new surface (that matches the backend of canvas)
3195 // for each shadow map
3196 sk_sp<SkSurface> surf(this->makeSurface(info));
3197
3198 // Wrap another SPFCanvas around the surface
3199 SkCanvas* depthMapCanvas = surf->getCanvas();
3200
3201 SkLights::Builder builder;
3202 builder.add(fLights->light(i));
3203 sk_sp<SkLights> curLight = builder.finish();
3204
3205 sk_sp<SkShader> shadowMapShader;
3206 shadowMapShader = SkRadialShadowMapShader::Make(
3207 povDepthShader, curLight,
3208 (int) picture->cullRect().width(),
3209 (int) picture->cullRect().height());
3210
3211 SkPaint shadowMapPaint;
3212 shadowMapPaint.setShader(std::move(shadowMapShader));
3213
3214 depthMapCanvas->setLights(curLight);
3215
3216 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3217 diffuseMap->height()),
3218 shadowMapPaint);
3219
3220 depthMap = surf->makeImageSnapshot();
3221
3222 } else {
3223 // TODO: compute the correct size of the depth map from the light properties
3224 // TODO: maybe add a kDepth_8_SkColorType
3225 // TODO: find actual max depth of picture
3226 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3227 fLights->light(i), 255,
3228 (int) picture->cullRect().width(),
3229 (int) picture->cullRect().height());
3230
3231 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3232 kBGRA_8888_SkColorType,
3233 kOpaque_SkAlphaType);
3234
3235 // Create a new surface (that matches the backend of canvas)
3236 // for each shadow map
3237 sk_sp<SkSurface> surf(this->makeSurface(info));
3238
3239 // Wrap another SPFCanvas around the surface
3240 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3241 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3242 depthMapCanvas->setShadowParams(params);
3243
3244 // set the depth map canvas to have the light we're drawing.
3245 SkLights::Builder builder;
3246 builder.add(fLights->light(i));
3247 sk_sp<SkLights> curLight = builder.finish();
3248 depthMapCanvas->setLights(std::move(curLight));
3249
3250 depthMapCanvas->drawPicture(picture);
3251 depthMap = surf->makeImageSnapshot();
3252 }
3253
3254 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3255 fLights->light(i).setShadowMap(std::move(depthMap));
3256 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3257 // we blur the variance map
3258 SkPaint blurPaint;
3259 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3260 params.fShadowRadius, nullptr));
3261
3262 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3263 kBGRA_8888_SkColorType,
3264 kOpaque_SkAlphaType);
3265
3266 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3267
3268 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3269
3270 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3271 }
3272 }
3273
3274 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003275 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3276 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003277 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003278 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003279 diffuseMap->height(),
3280 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003281
3282 shadowPaint.setShader(shadowShader);
3283
3284 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003285}
3286#endif
3287
reed@android.com8a1c16f2008-12-17 15:59:43 +00003288///////////////////////////////////////////////////////////////////////////////
3289///////////////////////////////////////////////////////////////////////////////
3290
reed3aafe112016-08-18 12:45:34 -07003291SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003292 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003293
3294 SkASSERT(canvas);
3295
reed3aafe112016-08-18 12:45:34 -07003296 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003297 fDone = !fImpl->next();
3298}
3299
3300SkCanvas::LayerIter::~LayerIter() {
3301 fImpl->~SkDrawIter();
3302}
3303
3304void SkCanvas::LayerIter::next() {
3305 fDone = !fImpl->next();
3306}
3307
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003308SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003309 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003310}
3311
3312const SkMatrix& SkCanvas::LayerIter::matrix() const {
3313 return fImpl->getMatrix();
3314}
3315
3316const SkPaint& SkCanvas::LayerIter::paint() const {
3317 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003318 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003319 paint = &fDefaultPaint;
3320 }
3321 return *paint;
3322}
3323
reed1e7f5e72016-04-27 07:49:17 -07003324const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003325int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3326int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003327
3328///////////////////////////////////////////////////////////////////////////////
3329
fmalitac3b589a2014-06-05 12:40:07 -07003330SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003331
3332///////////////////////////////////////////////////////////////////////////////
3333
3334static bool supported_for_raster_canvas(const SkImageInfo& info) {
3335 switch (info.alphaType()) {
3336 case kPremul_SkAlphaType:
3337 case kOpaque_SkAlphaType:
3338 break;
3339 default:
3340 return false;
3341 }
3342
3343 switch (info.colorType()) {
3344 case kAlpha_8_SkColorType:
3345 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003346 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003347 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003348 break;
3349 default:
3350 return false;
3351 }
3352
3353 return true;
3354}
3355
Mike Reed5df49342016-11-12 08:06:55 -06003356std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3357 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003358 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003359 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003360 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003361
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003362 SkBitmap bitmap;
3363 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003364 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003365 }
Mike Reed5df49342016-11-12 08:06:55 -06003366 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003367}
reedd5fa1a42014-08-09 11:08:05 -07003368
3369///////////////////////////////////////////////////////////////////////////////
3370
3371SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003372 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003373 : fCanvas(canvas)
3374 , fSaveCount(canvas->getSaveCount())
3375{
bsalomon49f085d2014-09-05 13:34:00 -07003376 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003377 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003378 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003379 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003380 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003381 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003382 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003383 canvas->save();
3384 }
mtklein6cfa73a2014-08-13 13:33:49 -07003385
bsalomon49f085d2014-09-05 13:34:00 -07003386 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003387 canvas->concat(*matrix);
3388 }
3389}
3390
3391SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3392 fCanvas->restoreToCount(fSaveCount);
3393}
reede8f30622016-03-23 18:59:25 -07003394
Florin Malitaee424ac2016-12-01 12:47:59 -05003395///////////////////////////////////////////////////////////////////////////////
3396
3397SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3398 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3399
Florin Malita439ace92016-12-02 12:05:41 -05003400SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3401 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3402
Florin Malitaee424ac2016-12-01 12:47:59 -05003403SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3404 (void)this->INHERITED::getSaveLayerStrategy(rec);
3405 return kNoLayer_SaveLayerStrategy;
3406}
3407
3408///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003409
reed73603f32016-09-20 08:42:38 -07003410static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3411static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3412static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3413static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3414static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3415static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003416
3417///////////////////////////////////////////////////////////////////////////////////////////////////
3418
3419SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3420 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3421 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3422 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3423 SkIPoint origin = dev->getOrigin();
3424 SkMatrix ctm = this->getTotalMatrix();
3425 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3426
3427 SkIRect clip = fMCRec->fRasterClip.getBounds();
3428 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003429 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003430 clip.setEmpty();
3431 }
3432
3433 fAllocator->updateHandle(handle, ctm, clip);
3434 return handle;
3435 }
3436 return nullptr;
3437}
3438
3439static bool install(SkBitmap* bm, const SkImageInfo& info,
3440 const SkRasterHandleAllocator::Rec& rec) {
3441 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3442 rec.fReleaseProc, rec.fReleaseCtx);
3443}
3444
3445SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3446 SkBitmap* bm) {
3447 SkRasterHandleAllocator::Rec rec;
3448 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3449 return nullptr;
3450 }
3451 return rec.fHandle;
3452}
3453
3454std::unique_ptr<SkCanvas>
3455SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3456 const SkImageInfo& info, const Rec* rec) {
3457 if (!alloc || !supported_for_raster_canvas(info)) {
3458 return nullptr;
3459 }
3460
3461 SkBitmap bm;
3462 Handle hndl;
3463
3464 if (rec) {
3465 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3466 } else {
3467 hndl = alloc->allocBitmap(info, &bm);
3468 }
3469 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3470}