blob: 0c6f241e9749f3b8d0c60f9d6e092c308979ae37 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060023#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080024#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000025#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050026#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070027#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070028#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070029#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000030#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070031#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000032#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050033#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070035#include "SkShadowPaintFilterCanvas.h"
36#include "SkShadowShader.h"
robertphillips4418dba2016-03-07 12:45:14 -080037#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000038#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070039#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000040#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000041#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080042#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070043#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080046#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000047#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070048#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050051#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050052#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053
reede3b38ce2016-01-08 09:18:44 -080054#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
55
reedc83a2972015-07-16 07:40:45 -070056/*
57 * Return true if the drawing this rect would hit every pixels in the canvas.
58 *
59 * Returns false if
60 * - rect does not contain the canvas' bounds
61 * - paint is not fill
62 * - paint would blur or otherwise change the coverage of the rect
63 */
64bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
65 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070066 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
67 (int)kNone_ShaderOverrideOpacity,
68 "need_matching_enums0");
69 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
70 (int)kOpaque_ShaderOverrideOpacity,
71 "need_matching_enums1");
72 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
73 (int)kNotOpaque_ShaderOverrideOpacity,
74 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070075
76 const SkISize size = this->getBaseLayerSize();
77 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
78 if (!this->getClipStack()->quickContains(bounds)) {
79 return false;
80 }
81
82 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070083 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070084 return false; // conservative
85 }
halcanaryc5769b22016-08-10 07:13:21 -070086
87 SkRect devRect;
88 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
89 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070090 return false;
91 }
92 }
93
94 if (paint) {
95 SkPaint::Style paintStyle = paint->getStyle();
96 if (!(paintStyle == SkPaint::kFill_Style ||
97 paintStyle == SkPaint::kStrokeAndFill_Style)) {
98 return false;
99 }
100 if (paint->getMaskFilter() || paint->getLooper()
101 || paint->getPathEffect() || paint->getImageFilter()) {
102 return false; // conservative
103 }
104 }
105 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
106}
107
108///////////////////////////////////////////////////////////////////////////////////////////////////
109
reedd990e2f2014-12-22 11:58:30 -0800110static bool gIgnoreSaveLayerBounds;
111void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
112 gIgnoreSaveLayerBounds = ignore;
113}
114bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
115 return gIgnoreSaveLayerBounds;
116}
117
reed0acf1b42014-12-22 16:12:38 -0800118static bool gTreatSpriteAsBitmap;
119void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
120 gTreatSpriteAsBitmap = spriteAsBitmap;
121}
122bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
123 return gTreatSpriteAsBitmap;
124}
125
reed@google.comda17f752012-08-16 18:27:05 +0000126// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127//#define SK_TRACE_SAVERESTORE
128
129#ifdef SK_TRACE_SAVERESTORE
130 static int gLayerCounter;
131 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
132 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
133
134 static int gRecCounter;
135 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
136 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
137
138 static int gCanvasCounter;
139 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
140 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
141#else
142 #define inc_layer()
143 #define dec_layer()
144 #define inc_rec()
145 #define dec_rec()
146 #define inc_canvas()
147 #define dec_canvas()
148#endif
149
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000150typedef SkTLazy<SkPaint> SkLazyPaint;
151
reedc83a2972015-07-16 07:40:45 -0700152void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000153 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700154 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
155 ? SkSurface::kDiscard_ContentChangeMode
156 : SkSurface::kRetain_ContentChangeMode);
157 }
158}
159
160void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
161 ShaderOverrideOpacity overrideOpacity) {
162 if (fSurfaceBase) {
163 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
164 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
165 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
166 // and therefore we don't care which mode we're in.
167 //
168 if (fSurfaceBase->outstandingImageSnapshot()) {
169 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
170 mode = SkSurface::kDiscard_ContentChangeMode;
171 }
172 }
173 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000174 }
175}
176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000179/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 The clip/matrix/proc are fields that reflect the top of the save/restore
181 stack. Whenever the canvas changes, it marks a dirty flag, and then before
182 these are used (assuming we're not on a layer) we rebuild these cache
183 values: they reflect the top of the save stack, but translated and clipped
184 by the device's XY offset and bitmap-bounds.
185*/
186struct DeviceCM {
187 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000188 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000189 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000190 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700191 const SkMatrix* fMatrix;
192 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700193 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194
reed96e657d2015-03-10 17:30:07 -0700195 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700196 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700197 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700198 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700199 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700200 {
reed2c9e2002016-07-25 08:05:22 -0700201 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000202 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700203 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000204 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000206 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700207 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700208 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000209 }
reed@google.com4b226022011-01-11 18:32:13 +0000210
mtkleinfeaadee2015-04-08 11:25:48 -0700211 void reset(const SkIRect& bounds) {
212 SkASSERT(!fPaint);
213 SkASSERT(!fNext);
214 SkASSERT(fDevice);
215 fClip.setRect(bounds);
216 }
217
reed@google.com045e62d2011-10-24 12:19:46 +0000218 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700219 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000220 int x = fDevice->getOrigin().x();
221 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 int width = fDevice->width();
223 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000224
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 if ((x | y) == 0) {
226 fMatrix = &totalMatrix;
227 fClip = totalClip;
228 } else {
229 fMatrixStorage = totalMatrix;
230 fMatrixStorage.postTranslate(SkIntToScalar(-x),
231 SkIntToScalar(-y));
232 fMatrix = &fMatrixStorage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 totalClip.translate(-x, -y, &fClip);
234 }
235
reed@google.com045e62d2011-10-24 12:19:46 +0000236 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
Mike Reedc42a1cd2017-02-14 14:25:14 -0500238#ifdef SK_USE_DEVICE_CLIPPING
239 SkASSERT(*fMatrix == fDevice->ctm());
240 // TODO: debug tiles-rt-8888 so we can enable this all the time
241// fDevice->validateDevBounds(fClip.getBounds());
242#endif
243
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000247 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248 SkRegion::kDifference_Op);
249 }
reed@google.com4b226022011-01-11 18:32:13 +0000250
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251#ifdef SK_DEBUG
252 if (!fClip.isEmpty()) {
253 SkIRect deviceR;
254 deviceR.set(0, 0, width, height);
255 SkASSERT(deviceR.contains(fClip.getBounds()));
256 }
257#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000258 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259};
260
261/* This is the record we keep for each save/restore level in the stack.
262 Since a level optionally copies the matrix and/or stack, we have pointers
263 for these fields. If the value is copied for this level, the copy is
264 stored in the ...Storage field, and the pointer points to that. If the
265 value is not copied for this level, we ignore ...Storage, and just point
266 at the corresponding value in the previous level in the stack.
267*/
268class SkCanvas::MCRec {
269public:
reed1f836ee2014-07-07 07:49:34 -0700270 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700271 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 /* If there are any layers in the stack, this points to the top-most
273 one that is at or below this level in the stack (so we know what
274 bitmap/device to draw into from this level. This value is NOT
275 reference counted, since the real owner is either our fLayer field,
276 or a previous one in a lower level.)
277 */
reed2ff1fce2014-12-11 07:07:37 -0800278 DeviceCM* fTopLayer;
279 SkRasterClip fRasterClip;
280 SkMatrix fMatrix;
281 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282
vjiaoblacke5de1302016-07-13 14:05:28 -0700283 // This is the current cumulative depth (aggregate of all done translateZ calls)
284 SkScalar fCurDrawDepth;
285
reedd9544982014-09-09 18:46:22 -0700286 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700287 fFilter = nullptr;
288 fLayer = nullptr;
289 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800290 fMatrix.reset();
291 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700292 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700293
reedd9544982014-09-09 18:46:22 -0700294 // don't bother initializing fNext
295 inc_rec();
296 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700297 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
298 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700299 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700300 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700301 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800302 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700303
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 // don't bother initializing fNext
305 inc_rec();
306 }
307 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000308 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700309 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310 dec_rec();
311 }
mtkleinfeaadee2015-04-08 11:25:48 -0700312
313 void reset(const SkIRect& bounds) {
314 SkASSERT(fLayer);
315 SkASSERT(fDeferredSaveCount == 0);
316
317 fMatrix.reset();
318 fRasterClip.setRect(bounds);
319 fLayer->reset(bounds);
320 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321};
322
reed02f9ed72016-09-06 09:06:18 -0700323static SkIRect compute_device_bounds(SkBaseDevice* device) {
324 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
325 device->width(), device->height());
326}
327
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328class SkDrawIter : public SkDraw {
329public:
reed3aafe112016-08-18 12:45:34 -0700330 SkDrawIter(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 canvas->updateDeviceCMCache();
332
bungeman6bd52842016-10-27 09:30:08 -0700333 fClipStack = canvas->getClipStack();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700335
336 fMultiDeviceCS = nullptr;
337 if (fCurrLayer->fNext) {
bungeman6bd52842016-10-27 09:30:08 -0700338 fMultiDeviceCS = canvas->fClipStack.get();
reed02f9ed72016-09-06 09:06:18 -0700339 fMultiDeviceCS->save();
340 }
341 }
342
343 ~SkDrawIter() {
344 if (fMultiDeviceCS) {
345 fMultiDeviceCS->restore();
346 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347 }
reed@google.com4b226022011-01-11 18:32:13 +0000348
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700350 if (fMultiDeviceCS && fDevice) {
351 // remove the previous device's bounds
Mike Reedc1f77742016-12-09 09:00:50 -0500352 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), kDifference_SkClipOp);
reed02f9ed72016-09-06 09:06:18 -0700353 }
354
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700356 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
357 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358 }
359
reed@google.comf68c5e22012-02-24 16:38:58 +0000360 const DeviceCM* rec = fCurrLayer;
361 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362
363 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000364 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700366 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700367 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700368 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000370 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371
372 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700373 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000374
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375 return true;
376 }
377 return false;
378 }
reed@google.com4b226022011-01-11 18:32:13 +0000379
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000380 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700381 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000382 int getX() const { return fDevice->getOrigin().x(); }
383 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000385 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000386
reed@android.com8a1c16f2008-12-17 15:59:43 +0000387private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388 const DeviceCM* fCurrLayer;
389 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700390 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000391
392 typedef SkDraw INHERITED;
393};
394
Mike Reed7627fa52017-02-08 10:07:53 -0500395#define FOR_EACH_TOP_DEVICE( code ) \
396 do { \
397 DeviceCM* layer = fMCRec->fTopLayer; \
398 while (layer) { \
399 SkBaseDevice* device = layer->fDevice; \
Mike Reedc42a1cd2017-02-14 14:25:14 -0500400 if (device) { \
401 code; \
402 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500403 layer = layer->fNext; \
404 } \
405 } while (0)
406
reed@android.com8a1c16f2008-12-17 15:59:43 +0000407/////////////////////////////////////////////////////////////////////////////
408
reeddbc3cef2015-04-29 12:18:57 -0700409static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
410 return lazy->isValid() ? lazy->get() : lazy->set(orig);
411}
412
413/**
414 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700415 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700416 */
reedd053ce92016-03-22 10:17:23 -0700417static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700418 SkImageFilter* imgf = paint.getImageFilter();
419 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700420 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700421 }
422
reedd053ce92016-03-22 10:17:23 -0700423 SkColorFilter* imgCFPtr;
424 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700425 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700426 }
reedd053ce92016-03-22 10:17:23 -0700427 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700428
429 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700430 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700431 // there is no existing paint colorfilter, so we can just return the imagefilter's
432 return imgCF;
433 }
434
435 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
436 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700437 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700438}
439
senorblanco87e066e2015-10-28 11:23:36 -0700440/**
441 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
442 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
443 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
444 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
445 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
446 * conservative "effective" bounds based on the settings in the paint... with one exception. This
447 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
448 * deliberately ignored.
449 */
450static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
451 const SkRect& rawBounds,
452 SkRect* storage) {
453 SkPaint tmpUnfiltered(paint);
454 tmpUnfiltered.setImageFilter(nullptr);
455 if (tmpUnfiltered.canComputeFastBounds()) {
456 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
457 } else {
458 return rawBounds;
459 }
460}
461
reed@android.com8a1c16f2008-12-17 15:59:43 +0000462class AutoDrawLooper {
463public:
senorblanco87e066e2015-10-28 11:23:36 -0700464 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
465 // paint. It's used to determine the size of the offscreen layer for filters.
466 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700467 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700468 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000469 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800470#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000471 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800472#else
473 fFilter = nullptr;
474#endif
reed4a8126e2014-09-22 07:29:03 -0700475 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000476 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700477 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000478 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000479
reedd053ce92016-03-22 10:17:23 -0700480 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700481 if (simplifiedCF) {
482 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700483 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700484 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700485 fPaint = paint;
486 }
487
488 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700489 /**
490 * We implement ImageFilters for a given draw by creating a layer, then applying the
491 * imagefilter to the pixels of that layer (its backing surface/image), and then
492 * we call restore() to xfer that layer to the main canvas.
493 *
494 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
495 * 2. Generate the src pixels:
496 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
497 * return (fPaint). We then draw the primitive (using srcover) into a cleared
498 * buffer/surface.
499 * 3. Restore the layer created in #1
500 * The imagefilter is passed the buffer/surface from the layer (now filled with the
501 * src pixels of the primitive). It returns a new "filtered" buffer, which we
502 * draw onto the previous layer using the xfermode from the original paint.
503 */
reed@google.com8926b162012-03-23 15:36:36 +0000504 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500505 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700506 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700507 SkRect storage;
508 if (rawBounds) {
509 // Make rawBounds include all paint outsets except for those due to image filters.
510 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
511 }
reedbfd5f172016-01-07 11:28:08 -0800512 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700513 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700514 fTempLayerForImageFilter = true;
515 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000516 }
517
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000518 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500519 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000520 fIsSimple = false;
521 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700522 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000523 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700524 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000525 }
526 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000527
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700529 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000530 fCanvas->internalRestore();
531 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000532 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000533 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000534
reed@google.com4e2b3d32011-04-07 14:18:59 +0000535 const SkPaint& paint() const {
536 SkASSERT(fPaint);
537 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000538 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000539
reed@google.com129ec222012-05-15 13:24:09 +0000540 bool next(SkDrawFilter::Type drawType) {
541 if (fDone) {
542 return false;
543 } else if (fIsSimple) {
544 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000545 return !fPaint->nothingToDraw();
546 } else {
547 return this->doNext(drawType);
548 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000549 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000550
reed@android.com8a1c16f2008-12-17 15:59:43 +0000551private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500552 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700553 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000554 SkCanvas* fCanvas;
555 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000556 SkDrawFilter* fFilter;
557 const SkPaint* fPaint;
558 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700559 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000560 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000561 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000562 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500563 char fStorage[48];
564 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000565
566 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000567};
568
reed@google.com129ec222012-05-15 13:24:09 +0000569bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700570 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000571 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700572 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000573
reeddbc3cef2015-04-29 12:18:57 -0700574 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
575 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000576
reed5c476fb2015-04-20 08:04:21 -0700577 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700578 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700579 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000580 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000581
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000582 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000583 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000584 return false;
585 }
586 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000587 if (!fFilter->filter(paint, drawType)) {
588 fDone = true;
589 return false;
590 }
halcanary96fcdcc2015-08-27 07:41:13 -0700591 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000592 // no looper means we only draw once
593 fDone = true;
594 }
595 }
596 fPaint = paint;
597
598 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000599 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000600 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000601 }
602
603 // call this after any possible paint modifiers
604 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700605 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000606 return false;
607 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000608 return true;
609}
610
reed@android.com8a1c16f2008-12-17 15:59:43 +0000611////////// macros to place around the internal draw calls //////////////////
612
reed3aafe112016-08-18 12:45:34 -0700613#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
614 this->predrawNotify(); \
615 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
616 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800617 SkDrawIter iter(this);
618
619
reed@google.com8926b162012-03-23 15:36:36 +0000620#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000621 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700622 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000623 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000624 SkDrawIter iter(this);
625
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000626#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000627 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700628 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000629 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000630 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000631
reedc83a2972015-07-16 07:40:45 -0700632#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
633 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700634 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700635 while (looper.next(type)) { \
636 SkDrawIter iter(this);
637
reed@google.com4e2b3d32011-04-07 14:18:59 +0000638#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000639
640////////////////////////////////////////////////////////////////////////////
641
msarettfbfa2582016-08-12 08:29:08 -0700642static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
643 if (bounds.isEmpty()) {
644 return SkRect::MakeEmpty();
645 }
646
647 // Expand bounds out by 1 in case we are anti-aliasing. We store the
648 // bounds as floats to enable a faster quick reject implementation.
649 SkRect dst;
650 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
651 return dst;
652}
653
mtkleinfeaadee2015-04-08 11:25:48 -0700654void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
655 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700656 fClipStack->reset();
657 fMCRec->reset(bounds);
658
659 // We're peering through a lot of structs here. Only at this scope do we
660 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
661 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700662 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700663 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700664}
665
reedd9544982014-09-09 18:46:22 -0700666SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800667 if (device && device->forceConservativeRasterClip()) {
668 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
669 }
670 // Since init() is only called once by our constructors, it is safe to perform this
671 // const-cast.
672 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
673
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000674 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700675 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800676 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700677 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700678#ifdef SK_EXPERIMENTAL_SHADOWING
679 fLights = nullptr;
680#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681
halcanary385fe4d2015-08-26 13:07:48 -0700682 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700683
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700685 new (fMCRec) MCRec(fConservativeRasterClip);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500686 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700687 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000688
reeda499f902015-05-01 09:34:31 -0700689 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
690 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700691 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700692 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700693
reed@android.com8a1c16f2008-12-17 15:59:43 +0000694 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000695
halcanary96fcdcc2015-08-27 07:41:13 -0700696 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000697
reedf92c8662014-08-18 08:02:43 -0700698 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700699 // The root device and the canvas should always have the same pixel geometry
700 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700701 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800702 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700703 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500704
705#ifdef SK_USE_DEVICE_CLIPPING
706 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
707#endif
reedf92c8662014-08-18 08:02:43 -0700708 }
msarettfbfa2582016-08-12 08:29:08 -0700709
reedf92c8662014-08-18 08:02:43 -0700710 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000711}
712
reed@google.comcde92112011-07-06 20:00:52 +0000713SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000714 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700715 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800716 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000717{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000718 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000719
halcanary96fcdcc2015-08-27 07:41:13 -0700720 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000721}
722
reedd9544982014-09-09 18:46:22 -0700723static SkBitmap make_nopixels(int width, int height) {
724 SkBitmap bitmap;
725 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
726 return bitmap;
727}
728
729class SkNoPixelsBitmapDevice : public SkBitmapDevice {
730public:
robertphillipsfcf78292015-06-19 11:49:52 -0700731 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
732 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800733 {
Mike Reedc42a1cd2017-02-14 14:25:14 -0500734 this->setOrigin(SkMatrix::I(), bounds.x(), bounds.y());
reed78e27682014-11-19 08:04:34 -0800735 }
reedd9544982014-09-09 18:46:22 -0700736
737private:
piotaixrb5fae932014-09-24 13:03:30 -0700738
reedd9544982014-09-09 18:46:22 -0700739 typedef SkBitmapDevice INHERITED;
740};
741
reed96a857e2015-01-25 10:33:58 -0800742SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000743 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800744 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800745 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000746{
747 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700748
halcanary385fe4d2015-08-26 13:07:48 -0700749 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
750 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700751}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000752
reed78e27682014-11-19 08:04:34 -0800753SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700754 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700755 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800756 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700757{
758 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700759
halcanary385fe4d2015-08-26 13:07:48 -0700760 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700761}
762
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000763SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000764 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700765 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800766 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000767{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700769
reedd9544982014-09-09 18:46:22 -0700770 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771}
772
robertphillipsfcf78292015-06-19 11:49:52 -0700773SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
774 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700775 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800776 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700777{
778 inc_canvas();
779
780 this->init(device, flags);
781}
782
reed4a8126e2014-09-22 07:29:03 -0700783SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700784 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700785 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800786 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700787{
788 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700789
Hal Canary704cd322016-11-07 14:13:52 -0500790 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
791 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700792}
reed29c857d2014-09-21 10:25:07 -0700793
Mike Reed356f7c22017-01-10 11:58:39 -0500794SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
795 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700796 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
797 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500798 , fAllocator(std::move(alloc))
reed42b73eb2015-11-20 13:42:42 -0800799 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700800{
801 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700802
Mike Reed356f7c22017-01-10 11:58:39 -0500803 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500804 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805}
806
Mike Reed356f7c22017-01-10 11:58:39 -0500807SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
808
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809SkCanvas::~SkCanvas() {
810 // free up the contents of our deque
811 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000812
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813 this->internalRestore(); // restore the last, since we're going away
814
halcanary385fe4d2015-08-26 13:07:48 -0700815 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000816
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817 dec_canvas();
818}
819
fmalita53d9f1c2016-01-25 06:23:54 -0800820#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821SkDrawFilter* SkCanvas::getDrawFilter() const {
822 return fMCRec->fFilter;
823}
824
825SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700826 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
828 return filter;
829}
fmalita77650002016-01-21 18:47:11 -0800830#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000832SkMetaData& SkCanvas::getMetaData() {
833 // metadata users are rare, so we lazily allocate it. If that changes we
834 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700835 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000836 fMetaData = new SkMetaData;
837 }
838 return *fMetaData;
839}
840
reed@android.com8a1c16f2008-12-17 15:59:43 +0000841///////////////////////////////////////////////////////////////////////////////
842
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000843void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700844 this->onFlush();
845}
846
847void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000848 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000849 if (device) {
850 device->flush();
851 }
852}
853
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000854SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000855 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000856 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
857}
858
senorblancoafc7cce2016-02-02 18:44:15 -0800859SkIRect SkCanvas::getTopLayerBounds() const {
860 SkBaseDevice* d = this->getTopDevice();
861 if (!d) {
862 return SkIRect::MakeEmpty();
863 }
864 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
865}
866
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000867SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000868 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000869 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000870 SkASSERT(rec && rec->fLayer);
871 return rec->fLayer->fDevice;
872}
873
Florin Malita0ed3b642017-01-13 16:56:38 +0000874SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000875 return fMCRec->fTopLayer->fDevice;
876}
877
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000878bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000879 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700880 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700881 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000882 return false;
883 }
884 weAllocated = true;
885 }
886
reedcf01e312015-05-23 19:14:51 -0700887 SkAutoPixmapUnlock unlocker;
888 if (bitmap->requestLock(&unlocker)) {
889 const SkPixmap& pm = unlocker.pixmap();
890 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
891 return true;
892 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000893 }
894
895 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500896 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000897 }
898 return false;
899}
reed@google.com51df9e32010-12-23 19:29:18 +0000900
bsalomon@google.comc6980972011-11-02 19:57:21 +0000901bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000902 SkIRect r = srcRect;
903 const SkISize size = this->getBaseLayerSize();
904 if (!r.intersect(0, 0, size.width(), size.height())) {
905 bitmap->reset();
906 return false;
907 }
908
reed84825042014-09-02 12:50:45 -0700909 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000910 // bitmap will already be reset.
911 return false;
912 }
913 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
914 bitmap->reset();
915 return false;
916 }
917 return true;
918}
919
reed96472de2014-12-10 09:53:42 -0800920bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000921 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000922 if (!device) {
923 return false;
924 }
mtkleinf0f14112014-12-12 08:46:25 -0800925
Matt Sarett03dd6d52017-01-23 12:15:09 -0500926 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000927}
928
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000929bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700930 SkAutoPixmapUnlock unlocker;
931 if (bitmap.requestLock(&unlocker)) {
932 const SkPixmap& pm = unlocker.pixmap();
933 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000934 }
935 return false;
936}
937
Matt Sarett03dd6d52017-01-23 12:15:09 -0500938bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000939 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000940 SkBaseDevice* device = this->getDevice();
941 if (!device) {
942 return false;
943 }
944
Matt Sarett03dd6d52017-01-23 12:15:09 -0500945 // This check gives us an early out and prevents generation ID churn on the surface.
946 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
947 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
948 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
949 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000950 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000951
Matt Sarett03dd6d52017-01-23 12:15:09 -0500952 // Tell our owning surface to bump its generation ID.
953 const bool completeOverwrite =
954 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700955 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700956
Matt Sarett03dd6d52017-01-23 12:15:09 -0500957 // This can still fail, most notably in the case of a invalid color type or alpha type
958 // conversion. We could pull those checks into this function and avoid the unnecessary
959 // generation ID bump. But then we would be performing those checks twice, since they
960 // are also necessary at the bitmap/pixmap entry points.
961 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000962}
reed@google.com51df9e32010-12-23 19:29:18 +0000963
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964//////////////////////////////////////////////////////////////////////////////
965
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966void SkCanvas::updateDeviceCMCache() {
967 if (fDeviceCMDirty) {
968 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700969 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000971
halcanary96fcdcc2015-08-27 07:41:13 -0700972 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700973 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000975 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976 do {
reedde6c5312016-09-02 12:10:07 -0700977 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700978 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979 }
980 fDeviceCMDirty = false;
981 }
982}
983
reed@android.com8a1c16f2008-12-17 15:59:43 +0000984///////////////////////////////////////////////////////////////////////////////
985
reed2ff1fce2014-12-11 07:07:37 -0800986void SkCanvas::checkForDeferredSave() {
987 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800988 this->doSave();
989 }
990}
991
reedf0090cb2014-11-26 08:55:51 -0800992int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800993#ifdef SK_DEBUG
994 int count = 0;
995 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
996 for (;;) {
997 const MCRec* rec = (const MCRec*)iter.next();
998 if (!rec) {
999 break;
1000 }
1001 count += 1 + rec->fDeferredSaveCount;
1002 }
1003 SkASSERT(count == fSaveCount);
1004#endif
1005 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001006}
1007
1008int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001009 fSaveCount += 1;
1010 fMCRec->fDeferredSaveCount += 1;
1011 return this->getSaveCount() - 1; // return our prev value
1012}
1013
1014void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001015 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001016
1017 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1018 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001019 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001020}
1021
1022void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001023 if (fMCRec->fDeferredSaveCount > 0) {
1024 SkASSERT(fSaveCount > 1);
1025 fSaveCount -= 1;
1026 fMCRec->fDeferredSaveCount -= 1;
1027 } else {
1028 // check for underflow
1029 if (fMCStack.count() > 1) {
1030 this->willRestore();
1031 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001032 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001033 this->internalRestore();
1034 this->didRestore();
1035 }
reedf0090cb2014-11-26 08:55:51 -08001036 }
1037}
1038
1039void SkCanvas::restoreToCount(int count) {
1040 // sanity check
1041 if (count < 1) {
1042 count = 1;
1043 }
mtkleinf0f14112014-12-12 08:46:25 -08001044
reedf0090cb2014-11-26 08:55:51 -08001045 int n = this->getSaveCount() - count;
1046 for (int i = 0; i < n; ++i) {
1047 this->restore();
1048 }
1049}
1050
reed2ff1fce2014-12-11 07:07:37 -08001051void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001052 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001053 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001055
reed687fa1c2015-04-07 08:00:56 -07001056 fClipStack->save();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001057#ifdef SK_USE_DEVICE_CLIPPING
1058 FOR_EACH_TOP_DEVICE(device->save());
1059#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001060}
1061
reed4960eee2015-12-18 07:09:18 -08001062bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001063 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064}
1065
reed4960eee2015-12-18 07:09:18 -08001066bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001067 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -05001068 SkIRect clipBounds = this->getDeviceClipBounds();
1069 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001070 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001071 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001072
reed96e657d2015-03-10 17:30:07 -07001073 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1074
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001075 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001076 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001077 if (bounds && !imageFilter->canComputeFastBounds()) {
1078 bounds = nullptr;
1079 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001080 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001081 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001082 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001083 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001084
reed96e657d2015-03-10 17:30:07 -07001085 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086 r.roundOut(&ir);
1087 // early exit if the layer's bounds are clipped out
1088 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001089 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001090 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001091 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001092 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001093 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001094 }
1095 } else { // no user bounds, so just use the clip
1096 ir = clipBounds;
1097 }
reed180aec42015-03-11 10:39:04 -07001098 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001099
reed4960eee2015-12-18 07:09:18 -08001100 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001101 // Simplify the current clips since they will be applied properly during restore()
Mike Reedc1f77742016-12-09 09:00:50 -05001102 fClipStack->clipDevRect(ir, kReplace_SkClipOp);
reed180aec42015-03-11 10:39:04 -07001103 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001104 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001105 }
1106
1107 if (intersection) {
1108 *intersection = ir;
1109 }
1110 return true;
1111}
1112
reed4960eee2015-12-18 07:09:18 -08001113
reed4960eee2015-12-18 07:09:18 -08001114int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1115 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001116}
1117
reed70ee31b2015-12-10 13:44:45 -08001118int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001119 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1120}
1121
1122int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1123 SaveLayerRec rec(origRec);
1124 if (gIgnoreSaveLayerBounds) {
1125 rec.fBounds = nullptr;
1126 }
1127 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1128 fSaveCount += 1;
1129 this->internalSaveLayer(rec, strategy);
1130 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001131}
1132
reeda2217ef2016-07-20 06:04:34 -07001133void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001134 SkBaseDevice* dst, const SkIPoint& dstOrigin,
1135 const SkMatrix& ctm, const SkClipStack* clipStack) {
reeda2217ef2016-07-20 06:04:34 -07001136 SkDraw draw;
1137 SkRasterClip rc;
1138 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1139 if (!dst->accessPixels(&draw.fDst)) {
1140 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001141 }
reeda2217ef2016-07-20 06:04:34 -07001142 draw.fMatrix = &SkMatrix::I();
1143 draw.fRC = &rc;
1144 draw.fClipStack = clipStack;
1145 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001146
1147 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001148 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001149
Mike Reedc42a1cd2017-02-14 14:25:14 -05001150 int x = src->getOrigin().x() - dstOrigin.x();
1151 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001152 auto special = src->snapSpecial();
1153 if (special) {
1154 dst->drawSpecial(draw, special.get(), x, y, p);
1155 }
robertphillips7354a4b2015-12-16 05:08:27 -08001156}
reed70ee31b2015-12-10 13:44:45 -08001157
reed129ed1c2016-02-22 06:42:31 -08001158static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1159 const SkPaint* paint) {
1160 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1161 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001162 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001163 const bool hasImageFilter = paint && paint->getImageFilter();
1164
1165 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1166 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1167 // force to L32
1168 return SkImageInfo::MakeN32(w, h, alphaType);
1169 } else {
1170 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001171 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001172 }
1173}
1174
reed4960eee2015-12-18 07:09:18 -08001175void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1176 const SkRect* bounds = rec.fBounds;
1177 const SkPaint* paint = rec.fPaint;
1178 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1179
reed8c30a812016-04-20 16:36:51 -07001180 SkLazyPaint lazyP;
1181 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1182 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001183 SkMatrix remainder;
1184 SkSize scale;
1185 /*
1186 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1187 * but they do handle scaling. To accommodate this, we do the following:
1188 *
1189 * 1. Stash off the current CTM
1190 * 2. Decompose the CTM into SCALE and REMAINDER
1191 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1192 * contains the REMAINDER
1193 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1194 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1195 * of the original imagefilter, and draw that (via drawSprite)
1196 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1197 *
1198 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1199 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1200 */
reed96a04f32016-04-25 09:25:15 -07001201 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001202 stashedMatrix.decomposeScale(&scale, &remainder))
1203 {
1204 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1205 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1206 SkPaint* p = lazyP.set(*paint);
1207 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1208 SkFilterQuality::kLow_SkFilterQuality,
1209 sk_ref_sp(imageFilter)));
1210 imageFilter = p->getImageFilter();
1211 paint = p;
1212 }
reed8c30a812016-04-20 16:36:51 -07001213
junov@chromium.orga907ac32012-02-24 21:54:07 +00001214 // do this before we create the layer. We don't call the public save() since
1215 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001216 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001217
1218 fDeviceCMDirty = true;
1219
1220 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001221 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001222 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223 }
1224
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001225 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1226 // the clipRectBounds() call above?
1227 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001228 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001229 }
1230
reed4960eee2015-12-18 07:09:18 -08001231 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001232 SkPixelGeometry geo = fProps.pixelGeometry();
1233 if (paint) {
reed76033be2015-03-14 10:54:31 -07001234 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001235 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001236 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001237 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001238 }
1239 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240
robertphillips5139e502016-07-19 05:10:40 -07001241 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001242 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001243 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001244 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001245 }
reedb2db8982014-11-13 12:41:02 -08001246
robertphillips5139e502016-07-19 05:10:40 -07001247 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001248 paint);
1249
Hal Canary704cd322016-11-07 14:13:52 -05001250 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001251 {
reed70ee31b2015-12-10 13:44:45 -08001252 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001253 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001254 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001255 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001256 preserveLCDText,
1257 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001258 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1259 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001260 return;
reed61f501f2015-04-29 08:34:00 -07001261 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001262 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001263#ifndef SK_USE_DEVICE_CLIPPING
1264 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1265#endif
robertphillips7354a4b2015-12-16 05:08:27 -08001266
Hal Canary704cd322016-11-07 14:13:52 -05001267 DeviceCM* layer =
1268 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001269
Mike Reedb43a3e02017-02-11 10:18:58 -05001270 // only have a "next" if this new layer doesn't affect the clip (rare)
1271 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272 fMCRec->fLayer = layer;
1273 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001274
1275 if (rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001276 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
reeda2217ef2016-07-20 06:04:34 -07001277 fMCRec->fMatrix, this->getClipStack());
1278 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001279
1280#ifdef SK_USE_DEVICE_CLIPPING
1281 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1282
1283 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1284 if (layer->fNext) {
1285 // need to punch a hole in the previous device, so we don't draw there, given that
1286 // the new top-layer will allow drawing to happen "below" it.
1287 SkRegion hole(ir);
1288 do {
1289 layer = layer->fNext;
1290 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1291 } while (layer->fNext);
1292 }
1293#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294}
1295
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001296int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001297 if (0xFF == alpha) {
1298 return this->saveLayer(bounds, nullptr);
1299 } else {
1300 SkPaint tmpPaint;
1301 tmpPaint.setAlpha(alpha);
1302 return this->saveLayer(bounds, &tmpPaint);
1303 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001304}
1305
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306void SkCanvas::internalRestore() {
1307 SkASSERT(fMCStack.count() != 0);
1308
1309 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310
reed687fa1c2015-04-07 08:00:56 -07001311 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001312
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001313 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314 DeviceCM* layer = fMCRec->fLayer; // may be null
1315 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001316 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317
1318 // now do the normal restore()
1319 fMCRec->~MCRec(); // balanced in save()
1320 fMCStack.pop_back();
1321 fMCRec = (MCRec*)fMCStack.back();
1322
Mike Reedc42a1cd2017-02-14 14:25:14 -05001323#ifdef SK_USE_DEVICE_CLIPPING
1324 if (fMCRec) {
1325 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1326 }
1327#endif
1328
reed@android.com8a1c16f2008-12-17 15:59:43 +00001329 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1330 since if we're being recorded, we don't want to record this (the
1331 recorder will have already recorded the restore).
1332 */
bsalomon49f085d2014-09-05 13:34:00 -07001333 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001334 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001335 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001336 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001337 // restore what we smashed in internalSaveLayer
1338 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001339 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001341 delete layer;
reedb679ca82015-04-07 04:40:48 -07001342 } else {
1343 // we're at the root
reeda499f902015-05-01 09:34:31 -07001344 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001345 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001346 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001347 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001348 }
msarettfbfa2582016-08-12 08:29:08 -07001349
1350 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001351 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001352 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1353 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001354}
1355
reede8f30622016-03-23 18:59:25 -07001356sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001357 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001358 props = &fProps;
1359 }
1360 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001361}
1362
reede8f30622016-03-23 18:59:25 -07001363sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001364 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001365 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001366}
1367
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001368SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001369 return this->onImageInfo();
1370}
1371
1372SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001373 SkBaseDevice* dev = this->getDevice();
1374 if (dev) {
1375 return dev->imageInfo();
1376 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001377 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001378 }
1379}
1380
brianosman898235c2016-04-06 07:38:23 -07001381bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001382 return this->onGetProps(props);
1383}
1384
1385bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001386 SkBaseDevice* dev = this->getDevice();
1387 if (dev) {
1388 if (props) {
1389 *props = fProps;
1390 }
1391 return true;
1392 } else {
1393 return false;
1394 }
1395}
1396
reed6ceeebd2016-03-09 14:26:26 -08001397bool SkCanvas::peekPixels(SkPixmap* pmap) {
1398 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001399}
1400
reed884e97c2015-05-26 11:31:54 -07001401bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001402 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001403 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001404}
1405
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001406void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001407 SkPixmap pmap;
1408 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001409 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001410 }
1411 if (info) {
1412 *info = pmap.info();
1413 }
1414 if (rowBytes) {
1415 *rowBytes = pmap.rowBytes();
1416 }
1417 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001418 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001419 }
reed884e97c2015-05-26 11:31:54 -07001420 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001421}
1422
reed884e97c2015-05-26 11:31:54 -07001423bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001424 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001425 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001426}
1427
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429
reed7503d602016-07-15 14:23:29 -07001430void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001431 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001432 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433 paint = &tmp;
1434 }
reed@google.com4b226022011-01-11 18:32:13 +00001435
reed@google.com8926b162012-03-23 15:36:36 +00001436 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001437
reed@android.com8a1c16f2008-12-17 15:59:43 +00001438 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001439 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001440 paint = &looper.paint();
1441 SkImageFilter* filter = paint->getImageFilter();
1442 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001443 if (filter) {
1444 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1445 if (specialImage) {
1446 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1447 }
reed@google.com76dd2772012-01-05 21:15:07 +00001448 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001449 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001450 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001451 }
reeda2217ef2016-07-20 06:04:34 -07001452
reed@google.com4e2b3d32011-04-07 14:18:59 +00001453 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001454}
1455
reed32704672015-12-16 08:27:10 -08001456/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001457
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001458void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001459 if (dx || dy) {
1460 this->checkForDeferredSave();
1461 fDeviceCMDirty = true;
1462 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001463
reedfe69b502016-09-12 06:31:48 -07001464 // Translate shouldn't affect the is-scale-translateness of the matrix.
1465 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001466
Mike Reedc42a1cd2017-02-14 14:25:14 -05001467#ifdef SK_USE_DEVICE_CLIPPING
1468 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1469#endif
1470
reedfe69b502016-09-12 06:31:48 -07001471 this->didTranslate(dx,dy);
1472 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001473}
1474
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001475void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001476 SkMatrix m;
1477 m.setScale(sx, sy);
1478 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001479}
1480
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001481void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001482 SkMatrix m;
1483 m.setRotate(degrees);
1484 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001485}
1486
bungeman7438bfc2016-07-12 15:01:19 -07001487void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1488 SkMatrix m;
1489 m.setRotate(degrees, px, py);
1490 this->concat(m);
1491}
1492
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001493void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001494 SkMatrix m;
1495 m.setSkew(sx, sy);
1496 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001497}
1498
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001499void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001500 if (matrix.isIdentity()) {
1501 return;
1502 }
1503
reed2ff1fce2014-12-11 07:07:37 -08001504 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001505 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001506 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001507 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001508
1509#ifdef SK_USE_DEVICE_CLIPPING
1510 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1511#endif
1512
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001513 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001514}
1515
reed8c30a812016-04-20 16:36:51 -07001516void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001517 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001518 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001519 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001520
1521#ifdef SK_USE_DEVICE_CLIPPING
1522 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1523#endif
reed8c30a812016-04-20 16:36:51 -07001524}
1525
1526void SkCanvas::setMatrix(const SkMatrix& matrix) {
1527 this->checkForDeferredSave();
1528 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001529 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001530}
1531
reed@android.com8a1c16f2008-12-17 15:59:43 +00001532void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001533 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001534}
1535
vjiaoblack95302da2016-07-21 10:25:54 -07001536#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001537void SkCanvas::translateZ(SkScalar z) {
1538 this->checkForDeferredSave();
1539 this->fMCRec->fCurDrawDepth += z;
1540 this->didTranslateZ(z);
1541}
1542
1543SkScalar SkCanvas::getZ() const {
1544 return this->fMCRec->fCurDrawDepth;
1545}
1546
vjiaoblack95302da2016-07-21 10:25:54 -07001547void SkCanvas::setLights(sk_sp<SkLights> lights) {
1548 this->fLights = lights;
1549}
1550
1551sk_sp<SkLights> SkCanvas::getLights() const {
1552 return this->fLights;
1553}
1554#endif
1555
reed@android.com8a1c16f2008-12-17 15:59:43 +00001556//////////////////////////////////////////////////////////////////////////////
1557
Mike Reedc1f77742016-12-09 09:00:50 -05001558void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001559 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001560 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1561 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001562}
1563
Mike Reedc1f77742016-12-09 09:00:50 -05001564void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001565 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001566
1567#ifdef SK_USE_DEVICE_CLIPPING
1568 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
1569#endif
1570
reedc64eff52015-11-21 12:39:45 -08001571 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001572 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1573 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1574 isAA);
reedc64eff52015-11-21 12:39:45 -08001575 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001576 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001577}
1578
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001579void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1580 fClipRestrictionRect = rect;
1581 fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
1582 if (!fClipRestrictionRect.isEmpty()) {
1583 this->checkForDeferredSave();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001584#ifdef SK_USE_DEVICE_CLIPPING
1585 SkRegion restrictRgn(fClipRestrictionRect);
1586 FOR_EACH_TOP_DEVICE(device->clipRegion(restrictRgn, SkClipOp::kIntersect));
1587#endif
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001588 AutoValidateClip avc(this);
1589 fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
1590 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
1591 fDeviceCMDirty = true;
1592 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1593 }
1594}
1595
Mike Reedc1f77742016-12-09 09:00:50 -05001596void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001597 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001598 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001599 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001600 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1601 } else {
1602 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001603 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001604}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001605
Mike Reedc1f77742016-12-09 09:00:50 -05001606void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001607 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001608
Brian Salomona3b45d42016-10-03 11:36:16 -04001609 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001610
Brian Salomona3b45d42016-10-03 11:36:16 -04001611 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001612
1613#ifdef SK_USE_DEVICE_CLIPPING
1614 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
1615#endif
1616
Brian Salomona3b45d42016-10-03 11:36:16 -04001617 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1618 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1619 isAA);
1620 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1621 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001622}
1623
Mike Reedc1f77742016-12-09 09:00:50 -05001624void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001625 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001626 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001627
1628 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1629 SkRect r;
1630 if (path.isRect(&r)) {
1631 this->onClipRect(r, op, edgeStyle);
1632 return;
1633 }
1634 SkRRect rrect;
1635 if (path.isOval(&r)) {
1636 rrect.setOval(r);
1637 this->onClipRRect(rrect, op, edgeStyle);
1638 return;
1639 }
1640 if (path.isRRect(&rrect)) {
1641 this->onClipRRect(rrect, op, edgeStyle);
1642 return;
1643 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001644 }
robertphillips39f05382015-11-24 09:30:12 -08001645
1646 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001647}
1648
Mike Reedc1f77742016-12-09 09:00:50 -05001649void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001650 AutoValidateClip avc(this);
1651
reed@android.com8a1c16f2008-12-17 15:59:43 +00001652 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001653 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001654
1655#ifdef SK_USE_DEVICE_CLIPPING
1656 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
1657#endif
1658
Brian Salomona3b45d42016-10-03 11:36:16 -04001659 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001660
Brian Salomona3b45d42016-10-03 11:36:16 -04001661 const SkPath* rasterClipPath = &path;
1662 const SkMatrix* matrix = &fMCRec->fMatrix;
1663 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001664 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001665 isAA = getClipStack()->asPath(&tempPath);
1666 rasterClipPath = &tempPath;
1667 matrix = &SkMatrix::I();
Mike Reedc1f77742016-12-09 09:00:50 -05001668 op = kReplace_SkClipOp;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001669 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001670 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1671 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001672 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001673}
1674
Mike Reedc1f77742016-12-09 09:00:50 -05001675void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001676 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001677 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001678}
1679
Mike Reedc1f77742016-12-09 09:00:50 -05001680void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001681#ifdef SK_USE_DEVICE_CLIPPING
1682 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
1683#endif
1684
reed@google.com5c3d1472011-02-22 19:12:23 +00001685 AutoValidateClip avc(this);
1686
reed@android.com8a1c16f2008-12-17 15:59:43 +00001687 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001688
reed@google.com5c3d1472011-02-22 19:12:23 +00001689 // todo: signal fClipStack that we have a region, and therefore (I guess)
1690 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001691 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001692
reed73603f32016-09-20 08:42:38 -07001693 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001694 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001695}
1696
reed@google.com819c9212011-02-23 18:56:55 +00001697#ifdef SK_DEBUG
1698void SkCanvas::validateClip() const {
1699 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001700 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001701 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001702 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001703 return;
1704 }
1705
reed@google.com819c9212011-02-23 18:56:55 +00001706 SkIRect ir;
1707 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001708 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001709
reed687fa1c2015-04-07 08:00:56 -07001710 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001711 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001712 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001713 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001714 case SkClipStack::Element::kRect_Type:
1715 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001716 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001717 break;
1718 case SkClipStack::Element::kEmpty_Type:
1719 tmpClip.setEmpty();
1720 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001721 default: {
1722 SkPath path;
1723 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001724 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1725 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001726 break;
1727 }
reed@google.com819c9212011-02-23 18:56:55 +00001728 }
1729 }
reed@google.com819c9212011-02-23 18:56:55 +00001730}
1731#endif
1732
reed@google.com90c07ea2012-04-13 13:50:27 +00001733void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001734 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001735 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001736
halcanary96fcdcc2015-08-27 07:41:13 -07001737 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001738 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001739 }
1740}
1741
reed@google.com5c3d1472011-02-22 19:12:23 +00001742///////////////////////////////////////////////////////////////////////////////
1743
reed@google.com754de5f2014-02-24 19:38:20 +00001744bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001745 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001746}
1747
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001748bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001749 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001750}
1751
msarettfbfa2582016-08-12 08:29:08 -07001752static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1753#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1754 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1755 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1756 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1757 return 0xF != _mm_movemask_ps(mask);
1758#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1759 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1760 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1761 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1762 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1763#else
1764 SkRect devRectAsRect;
1765 SkRect devClipAsRect;
1766 devRect.store(&devRectAsRect.fLeft);
1767 devClip.store(&devClipAsRect.fLeft);
1768 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1769#endif
1770}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001771
msarettfbfa2582016-08-12 08:29:08 -07001772// It's important for this function to not be inlined. Otherwise the compiler will share code
1773// between the fast path and the slow path, resulting in two slow paths.
1774static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1775 const SkMatrix& matrix) {
1776 SkRect deviceRect;
1777 matrix.mapRect(&deviceRect, src);
1778 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1779}
1780
1781bool SkCanvas::quickReject(const SkRect& src) const {
1782#ifdef SK_DEBUG
1783 // Verify that fDeviceClipBounds are set properly.
1784 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001785 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001786 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001787 } else {
msarettfbfa2582016-08-12 08:29:08 -07001788 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001789 }
msarettfbfa2582016-08-12 08:29:08 -07001790
msarett9637ea92016-08-18 14:03:30 -07001791 // Verify that fIsScaleTranslate is set properly.
1792 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001793#endif
1794
msarett9637ea92016-08-18 14:03:30 -07001795 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001796 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1797 }
1798
1799 // We inline the implementation of mapScaleTranslate() for the fast path.
1800 float sx = fMCRec->fMatrix.getScaleX();
1801 float sy = fMCRec->fMatrix.getScaleY();
1802 float tx = fMCRec->fMatrix.getTranslateX();
1803 float ty = fMCRec->fMatrix.getTranslateY();
1804 Sk4f scale(sx, sy, sx, sy);
1805 Sk4f trans(tx, ty, tx, ty);
1806
1807 // Apply matrix.
1808 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1809
1810 // Make sure left < right, top < bottom.
1811 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1812 Sk4f min = Sk4f::Min(ltrb, rblt);
1813 Sk4f max = Sk4f::Max(ltrb, rblt);
1814 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1815 // ARM this sequence generates the fastest (a single instruction).
1816 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1817
1818 // Check if the device rect is NaN or outside the clip.
1819 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001820}
1821
reed@google.com3b3e8952012-08-16 20:53:31 +00001822bool SkCanvas::quickReject(const SkPath& path) const {
1823 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001824}
1825
Mike Reed42e8c532017-01-23 14:09:13 -05001826SkRect SkCanvas::onGetLocalClipBounds() const {
1827 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001828 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001829 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001830 }
1831
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001832 SkMatrix inverse;
1833 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001834 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001835 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001836 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001837
Mike Reed42e8c532017-01-23 14:09:13 -05001838 SkRect bounds;
1839 SkRect r;
1840 // adjust it outwards in case we are antialiasing
1841 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001842
Mike Reed42e8c532017-01-23 14:09:13 -05001843 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1844 ibounds.fRight + inset, ibounds.fBottom + inset);
1845 inverse.mapRect(&bounds, r);
1846 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001847}
1848
Mike Reed42e8c532017-01-23 14:09:13 -05001849SkIRect SkCanvas::onGetDeviceClipBounds() const {
reed1f836ee2014-07-07 07:49:34 -07001850 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001851 if (clip.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001852 return SkIRect::MakeEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001853 }
Mike Reed42e8c532017-01-23 14:09:13 -05001854 return clip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001855}
1856
reed@android.com8a1c16f2008-12-17 15:59:43 +00001857const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001858 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001859}
1860
Mike Reed3726a4a2017-01-19 11:36:41 -05001861void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1862 // we know that ganesh doesn't track the rgn, so ask for its clipstack
1863 if (this->getGrContext()) {
1864 SkPath path;
1865 this->getClipStack()->asPath(&path);
1866 SkISize size = this->getBaseLayerSize();
1867 rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
1868 } else {
1869 *rgn = fMCRec->fRasterClip.forceGetBW();
1870 }
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001871}
1872
Brian Osman11052242016-10-27 14:47:55 -04001873GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001874 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001875 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001876}
1877
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001878GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001879 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001880 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001881}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001882
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001883void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1884 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001885 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001886 if (outer.isEmpty()) {
1887 return;
1888 }
1889 if (inner.isEmpty()) {
1890 this->drawRRect(outer, paint);
1891 return;
1892 }
1893
1894 // We don't have this method (yet), but technically this is what we should
1895 // be able to assert...
1896 // SkASSERT(outer.contains(inner));
1897 //
1898 // For now at least check for containment of bounds
1899 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1900
1901 this->onDrawDRRect(outer, inner, paint);
1902}
1903
reed41af9662015-01-05 07:49:08 -08001904// These need to stop being virtual -- clients need to override the onDraw... versions
1905
1906void SkCanvas::drawPaint(const SkPaint& paint) {
1907 this->onDrawPaint(paint);
1908}
1909
1910void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1911 this->onDrawRect(r, paint);
1912}
1913
msarettdca352e2016-08-26 06:37:45 -07001914void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1915 if (region.isEmpty()) {
1916 return;
1917 }
1918
1919 if (region.isRect()) {
1920 return this->drawIRect(region.getBounds(), paint);
1921 }
1922
1923 this->onDrawRegion(region, paint);
1924}
1925
reed41af9662015-01-05 07:49:08 -08001926void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1927 this->onDrawOval(r, paint);
1928}
1929
1930void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1931 this->onDrawRRect(rrect, paint);
1932}
1933
1934void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1935 this->onDrawPoints(mode, count, pts, paint);
1936}
1937
1938void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001939 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001940 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001941 this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices,
1942 indexCount, paint);
1943}
1944
1945void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint,
1946 uint32_t flags) {
1947 RETURN_ON_NULL(vertices);
1948 this->onDrawVerticesObject(std::move(vertices), mode, paint, flags);
reed41af9662015-01-05 07:49:08 -08001949}
1950
1951void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1952 this->onDrawPath(path, paint);
1953}
1954
reeda85d4d02015-05-06 12:56:48 -07001955void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001956 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001957 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001958}
1959
reede47829b2015-08-06 10:02:53 -07001960void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1961 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001962 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001963 if (dst.isEmpty() || src.isEmpty()) {
1964 return;
1965 }
1966 this->onDrawImageRect(image, &src, dst, paint, constraint);
1967}
reed41af9662015-01-05 07:49:08 -08001968
reed84984ef2015-07-17 07:09:43 -07001969void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1970 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001971 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001972 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001973}
1974
reede47829b2015-08-06 10:02:53 -07001975void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1976 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001977 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001978 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1979 constraint);
1980}
reede47829b2015-08-06 10:02:53 -07001981
reed4c21dc52015-06-25 12:32:03 -07001982void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1983 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001984 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001985 if (dst.isEmpty()) {
1986 return;
1987 }
msarett552bca92016-08-03 06:53:26 -07001988 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1989 this->onDrawImageNine(image, center, dst, paint);
1990 } else {
reede47829b2015-08-06 10:02:53 -07001991 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001992 }
reed4c21dc52015-06-25 12:32:03 -07001993}
1994
msarett16882062016-08-16 09:31:08 -07001995void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1996 const SkPaint* paint) {
1997 RETURN_ON_NULL(image);
1998 if (dst.isEmpty()) {
1999 return;
2000 }
msarett71df2d72016-09-30 12:41:42 -07002001
2002 SkIRect bounds;
2003 Lattice latticePlusBounds = lattice;
2004 if (!latticePlusBounds.fBounds) {
2005 bounds = SkIRect::MakeWH(image->width(), image->height());
2006 latticePlusBounds.fBounds = &bounds;
2007 }
2008
2009 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
2010 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07002011 } else {
2012 this->drawImageRect(image, dst, paint);
2013 }
2014}
2015
reed41af9662015-01-05 07:49:08 -08002016void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002017 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002018 return;
2019 }
reed41af9662015-01-05 07:49:08 -08002020 this->onDrawBitmap(bitmap, dx, dy, paint);
2021}
2022
reede47829b2015-08-06 10:02:53 -07002023void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002024 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002025 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002026 return;
2027 }
reede47829b2015-08-06 10:02:53 -07002028 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002029}
2030
reed84984ef2015-07-17 07:09:43 -07002031void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2032 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002033 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002034}
2035
reede47829b2015-08-06 10:02:53 -07002036void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2037 SrcRectConstraint constraint) {
2038 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2039 constraint);
2040}
reede47829b2015-08-06 10:02:53 -07002041
reed41af9662015-01-05 07:49:08 -08002042void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2043 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002044 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002045 return;
2046 }
msarett552bca92016-08-03 06:53:26 -07002047 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2048 this->onDrawBitmapNine(bitmap, center, dst, paint);
2049 } else {
reeda5517e22015-07-14 10:54:12 -07002050 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002051 }
reed41af9662015-01-05 07:49:08 -08002052}
2053
msarettc573a402016-08-02 08:05:56 -07002054void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2055 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002056 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002057 return;
2058 }
msarett71df2d72016-09-30 12:41:42 -07002059
2060 SkIRect bounds;
2061 Lattice latticePlusBounds = lattice;
2062 if (!latticePlusBounds.fBounds) {
2063 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2064 latticePlusBounds.fBounds = &bounds;
2065 }
2066
2067 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2068 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002069 } else {
msarett16882062016-08-16 09:31:08 -07002070 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002071 }
msarettc573a402016-08-02 08:05:56 -07002072}
2073
reed71c3c762015-06-24 10:29:17 -07002074void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002075 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002076 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002077 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002078 if (count <= 0) {
2079 return;
2080 }
Joe Gregorioc4859072017-01-20 14:21:27 +00002081 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002082 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002083 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002084}
2085
reedf70b5312016-03-04 16:36:20 -08002086void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2087 if (key) {
2088 this->onDrawAnnotation(rect, key, value);
2089 }
2090}
2091
reede47829b2015-08-06 10:02:53 -07002092void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2093 const SkPaint* paint, SrcRectConstraint constraint) {
2094 if (src) {
2095 this->drawImageRect(image, *src, dst, paint, constraint);
2096 } else {
2097 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2098 dst, paint, constraint);
2099 }
2100}
2101void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2102 const SkPaint* paint, SrcRectConstraint constraint) {
2103 if (src) {
2104 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2105 } else {
2106 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2107 dst, paint, constraint);
2108 }
2109}
2110
tomhudsoncb3bd182016-05-18 07:24:16 -07002111void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2112 SkIRect layer_bounds = this->getTopLayerBounds();
2113 if (matrix) {
2114 *matrix = this->getTotalMatrix();
2115 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2116 }
2117 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05002118 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07002119 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2120 }
2121}
2122
reed@android.com8a1c16f2008-12-17 15:59:43 +00002123//////////////////////////////////////////////////////////////////////////////
2124// These are the virtual drawing methods
2125//////////////////////////////////////////////////////////////////////////////
2126
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002127void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002128 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002129 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2130 }
2131}
2132
reed41af9662015-01-05 07:49:08 -08002133void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002134 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002135 this->internalDrawPaint(paint);
2136}
2137
2138void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002139 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002140
2141 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002142 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002143 }
2144
reed@google.com4e2b3d32011-04-07 14:18:59 +00002145 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002146}
2147
reed41af9662015-01-05 07:49:08 -08002148void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2149 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002150 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151 if ((long)count <= 0) {
2152 return;
2153 }
2154
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002155 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002156 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002157 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002158 // special-case 2 points (common for drawing a single line)
2159 if (2 == count) {
2160 r.set(pts[0], pts[1]);
2161 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002162 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002163 }
senorblanco87e066e2015-10-28 11:23:36 -07002164 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2165 return;
2166 }
2167 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002168 }
reed@google.coma584aed2012-05-16 14:06:02 +00002169
halcanary96fcdcc2015-08-27 07:41:13 -07002170 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002171
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002172 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002173
reed@android.com8a1c16f2008-12-17 15:59:43 +00002174 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002175 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002176 }
reed@google.com4b226022011-01-11 18:32:13 +00002177
reed@google.com4e2b3d32011-04-07 14:18:59 +00002178 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002179}
2180
reed4a167172016-08-18 17:15:25 -07002181static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2182 return ((intptr_t)paint.getImageFilter() |
2183#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2184 (intptr_t)canvas->getDrawFilter() |
2185#endif
2186 (intptr_t)paint.getLooper() ) != 0;
2187}
2188
reed41af9662015-01-05 07:49:08 -08002189void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002190 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002191 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002192 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002193 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002194 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2195 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2196 SkRect tmp(r);
2197 tmp.sort();
2198
senorblanco87e066e2015-10-28 11:23:36 -07002199 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2200 return;
2201 }
2202 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002203 }
reed@google.com4b226022011-01-11 18:32:13 +00002204
reed4a167172016-08-18 17:15:25 -07002205 if (needs_autodrawlooper(this, paint)) {
2206 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002207
reed4a167172016-08-18 17:15:25 -07002208 while (iter.next()) {
2209 iter.fDevice->drawRect(iter, r, looper.paint());
2210 }
2211
2212 LOOPER_END
2213 } else {
2214 this->predrawNotify(bounds, &paint, false);
2215 SkDrawIter iter(this);
2216 while (iter.next()) {
2217 iter.fDevice->drawRect(iter, r, paint);
2218 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002219 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002220}
2221
msarett44df6512016-08-25 13:54:30 -07002222void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2223 SkRect storage;
2224 SkRect regionRect = SkRect::Make(region.getBounds());
2225 const SkRect* bounds = nullptr;
2226 if (paint.canComputeFastBounds()) {
2227 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2228 return;
2229 }
2230 bounds = &regionRect;
2231 }
2232
2233 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2234
2235 while (iter.next()) {
2236 iter.fDevice->drawRegion(iter, region, looper.paint());
2237 }
2238
2239 LOOPER_END
2240}
2241
reed41af9662015-01-05 07:49:08 -08002242void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002243 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002244 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002245 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002246 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002247 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2248 return;
2249 }
2250 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002251 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002252
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002253 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002254
2255 while (iter.next()) {
2256 iter.fDevice->drawOval(iter, oval, looper.paint());
2257 }
2258
2259 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002260}
2261
bsalomonac3aa242016-08-19 11:25:19 -07002262void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2263 SkScalar sweepAngle, bool useCenter,
2264 const SkPaint& paint) {
2265 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2266 const SkRect* bounds = nullptr;
2267 if (paint.canComputeFastBounds()) {
2268 SkRect storage;
2269 // Note we're using the entire oval as the bounds.
2270 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2271 return;
2272 }
2273 bounds = &oval;
2274 }
2275
2276 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2277
2278 while (iter.next()) {
2279 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2280 }
2281
2282 LOOPER_END
2283}
2284
reed41af9662015-01-05 07:49:08 -08002285void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002286 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002287 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002288 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002289 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002290 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2291 return;
2292 }
2293 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002294 }
2295
2296 if (rrect.isRect()) {
2297 // call the non-virtual version
2298 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002299 return;
2300 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002301 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002302 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2303 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002304 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002305
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002306 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002307
2308 while (iter.next()) {
2309 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2310 }
2311
2312 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002313}
2314
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002315void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2316 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002317 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002318 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002319 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002320 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2321 return;
2322 }
2323 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002324 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002325
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002326 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002327
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002328 while (iter.next()) {
2329 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2330 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002331
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002332 LOOPER_END
2333}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002334
reed41af9662015-01-05 07:49:08 -08002335void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002336 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002337 if (!path.isFinite()) {
2338 return;
2339 }
2340
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002341 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002342 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002343 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002344 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002345 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2346 return;
2347 }
2348 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002349 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002350
2351 const SkRect& r = path.getBounds();
2352 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002353 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002354 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002355 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002356 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002357 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002358
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002359 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002360
2361 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002362 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002363 }
2364
reed@google.com4e2b3d32011-04-07 14:18:59 +00002365 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002366}
2367
reed262a71b2015-12-05 13:07:27 -08002368bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002369 if (!paint.getImageFilter()) {
2370 return false;
2371 }
2372
2373 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002374 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002375 return false;
2376 }
2377
2378 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2379 // Once we can filter and the filter will return a result larger than itself, we should be
2380 // able to remove this constraint.
2381 // skbug.com/4526
2382 //
2383 SkPoint pt;
2384 ctm.mapXY(x, y, &pt);
2385 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2386 return ir.contains(fMCRec->fRasterClip.getBounds());
2387}
2388
reeda85d4d02015-05-06 12:56:48 -07002389void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002390 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002391 SkRect bounds = SkRect::MakeXYWH(x, y,
2392 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002393 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002394 SkRect tmp = bounds;
2395 if (paint) {
2396 paint->computeFastBounds(tmp, &tmp);
2397 }
2398 if (this->quickReject(tmp)) {
2399 return;
2400 }
reeda85d4d02015-05-06 12:56:48 -07002401 }
halcanary9d524f22016-03-29 09:03:52 -07002402
reeda85d4d02015-05-06 12:56:48 -07002403 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002404 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002405 paint = lazy.init();
2406 }
reed262a71b2015-12-05 13:07:27 -08002407
reeda2217ef2016-07-20 06:04:34 -07002408 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002409 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2410 *paint);
2411 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002412 special = this->getDevice()->makeSpecial(image);
2413 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002414 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002415 }
2416 }
2417
reed262a71b2015-12-05 13:07:27 -08002418 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2419
reeda85d4d02015-05-06 12:56:48 -07002420 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002421 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002422 if (special) {
2423 SkPoint pt;
2424 iter.fMatrix->mapXY(x, y, &pt);
2425 iter.fDevice->drawSpecial(iter, special.get(),
2426 SkScalarRoundToInt(pt.fX),
2427 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002428 } else {
2429 iter.fDevice->drawImage(iter, image, x, y, pnt);
2430 }
reeda85d4d02015-05-06 12:56:48 -07002431 }
halcanary9d524f22016-03-29 09:03:52 -07002432
reeda85d4d02015-05-06 12:56:48 -07002433 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002434}
2435
reed41af9662015-01-05 07:49:08 -08002436void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002437 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002438 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002439 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002440 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002441 if (paint) {
2442 paint->computeFastBounds(dst, &storage);
2443 }
2444 if (this->quickReject(storage)) {
2445 return;
2446 }
reeda85d4d02015-05-06 12:56:48 -07002447 }
2448 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002449 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002450 paint = lazy.init();
2451 }
halcanary9d524f22016-03-29 09:03:52 -07002452
senorblancoc41e7e12015-12-07 12:51:30 -08002453 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002454 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002455
reeda85d4d02015-05-06 12:56:48 -07002456 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002457 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002458 }
halcanary9d524f22016-03-29 09:03:52 -07002459
reeda85d4d02015-05-06 12:56:48 -07002460 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002461}
2462
reed41af9662015-01-05 07:49:08 -08002463void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002464 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002465 SkDEBUGCODE(bitmap.validate();)
2466
reed33366972015-10-08 09:22:02 -07002467 if (bitmap.drawsNothing()) {
2468 return;
2469 }
2470
2471 SkLazyPaint lazy;
2472 if (nullptr == paint) {
2473 paint = lazy.init();
2474 }
2475
2476 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2477
2478 SkRect storage;
2479 const SkRect* bounds = nullptr;
2480 if (paint->canComputeFastBounds()) {
2481 bitmap.getBounds(&storage);
2482 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002483 SkRect tmp = storage;
2484 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2485 return;
2486 }
2487 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488 }
reed@google.com4b226022011-01-11 18:32:13 +00002489
reeda2217ef2016-07-20 06:04:34 -07002490 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002491 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2492 *paint);
2493 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002494 special = this->getDevice()->makeSpecial(bitmap);
2495 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002496 drawAsSprite = false;
2497 }
2498 }
2499
reed262a71b2015-12-05 13:07:27 -08002500 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002501
2502 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002503 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002504 if (special) {
reed262a71b2015-12-05 13:07:27 -08002505 SkPoint pt;
2506 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002507 iter.fDevice->drawSpecial(iter, special.get(),
2508 SkScalarRoundToInt(pt.fX),
2509 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002510 } else {
2511 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2512 }
reed33366972015-10-08 09:22:02 -07002513 }
msarettfbfa2582016-08-12 08:29:08 -07002514
reed33366972015-10-08 09:22:02 -07002515 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002516}
2517
reed@google.com9987ec32011-09-07 11:57:52 +00002518// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002519void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002520 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002521 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002522 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002523 return;
2524 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002525
halcanary96fcdcc2015-08-27 07:41:13 -07002526 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002527 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002528 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2529 return;
2530 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002531 }
reed@google.com3d608122011-11-21 15:16:16 +00002532
reed@google.com33535f32012-09-25 15:37:50 +00002533 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002534 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002535 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002536 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002537
senorblancoc41e7e12015-12-07 12:51:30 -08002538 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002539 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002540
reed@google.com33535f32012-09-25 15:37:50 +00002541 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002542 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002543 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002544
reed@google.com33535f32012-09-25 15:37:50 +00002545 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002546}
2547
reed41af9662015-01-05 07:49:08 -08002548void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002549 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002550 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002551 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002552 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002553}
2554
reed4c21dc52015-06-25 12:32:03 -07002555void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2556 const SkPaint* paint) {
2557 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002558
halcanary96fcdcc2015-08-27 07:41:13 -07002559 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002560 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002561 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2562 return;
2563 }
reed@google.com3d608122011-11-21 15:16:16 +00002564 }
halcanary9d524f22016-03-29 09:03:52 -07002565
reed4c21dc52015-06-25 12:32:03 -07002566 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002567 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002568 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002569 }
halcanary9d524f22016-03-29 09:03:52 -07002570
senorblancoc41e7e12015-12-07 12:51:30 -08002571 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002572
reed4c21dc52015-06-25 12:32:03 -07002573 while (iter.next()) {
2574 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002575 }
halcanary9d524f22016-03-29 09:03:52 -07002576
reed4c21dc52015-06-25 12:32:03 -07002577 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002578}
2579
reed41af9662015-01-05 07:49:08 -08002580void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2581 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002582 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002583 SkDEBUGCODE(bitmap.validate();)
2584
halcanary96fcdcc2015-08-27 07:41:13 -07002585 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002586 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002587 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2588 return;
2589 }
reed4c21dc52015-06-25 12:32:03 -07002590 }
halcanary9d524f22016-03-29 09:03:52 -07002591
reed4c21dc52015-06-25 12:32:03 -07002592 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002593 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002594 paint = lazy.init();
2595 }
halcanary9d524f22016-03-29 09:03:52 -07002596
senorblancoc41e7e12015-12-07 12:51:30 -08002597 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002598
reed4c21dc52015-06-25 12:32:03 -07002599 while (iter.next()) {
2600 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2601 }
halcanary9d524f22016-03-29 09:03:52 -07002602
reed4c21dc52015-06-25 12:32:03 -07002603 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002604}
2605
msarett16882062016-08-16 09:31:08 -07002606void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2607 const SkPaint* paint) {
2608 if (nullptr == paint || paint->canComputeFastBounds()) {
2609 SkRect storage;
2610 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2611 return;
2612 }
2613 }
2614
2615 SkLazyPaint lazy;
2616 if (nullptr == paint) {
2617 paint = lazy.init();
2618 }
2619
2620 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2621
2622 while (iter.next()) {
2623 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2624 }
2625
2626 LOOPER_END
2627}
2628
2629void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2630 const SkRect& dst, const SkPaint* paint) {
2631 if (nullptr == paint || paint->canComputeFastBounds()) {
2632 SkRect storage;
2633 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2634 return;
2635 }
2636 }
2637
2638 SkLazyPaint lazy;
2639 if (nullptr == paint) {
2640 paint = lazy.init();
2641 }
2642
2643 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2644
2645 while (iter.next()) {
2646 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2647 }
2648
2649 LOOPER_END
2650}
2651
reed@google.comf67e4cf2011-03-15 20:56:58 +00002652class SkDeviceFilteredPaint {
2653public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002654 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002655 uint32_t filteredFlags = device->filterTextFlags(paint);
2656 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002657 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002658 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002659 fPaint = newPaint;
2660 } else {
2661 fPaint = &paint;
2662 }
2663 }
2664
reed@google.comf67e4cf2011-03-15 20:56:58 +00002665 const SkPaint& paint() const { return *fPaint; }
2666
2667private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002668 const SkPaint* fPaint;
2669 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002670};
2671
bungeman@google.com52c748b2011-08-22 21:30:43 +00002672void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2673 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002674 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002675 draw.fDevice->drawRect(draw, r, paint);
2676 } else {
2677 SkPaint p(paint);
Mike Reeda99b6ce2017-02-04 11:04:26 -05002678 p.setStrokeWidth(textSize * paint.getStrokeWidth());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002679 draw.fDevice->drawRect(draw, r, p);
2680 }
2681}
2682
2683void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2684 const char text[], size_t byteLength,
2685 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002686 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002687
2688 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002689 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002690 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002691 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002692 return;
2693 }
2694
2695 SkScalar width = 0;
2696 SkPoint start;
2697
2698 start.set(0, 0); // to avoid warning
2699 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2700 SkPaint::kStrikeThruText_Flag)) {
2701 width = paint.measureText(text, byteLength);
2702
2703 SkScalar offsetX = 0;
2704 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2705 offsetX = SkScalarHalf(width);
2706 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2707 offsetX = width;
2708 }
2709 start.set(x - offsetX, y);
2710 }
2711
2712 if (0 == width) {
2713 return;
2714 }
2715
2716 uint32_t flags = paint.getFlags();
2717
2718 if (flags & (SkPaint::kUnderlineText_Flag |
2719 SkPaint::kStrikeThruText_Flag)) {
2720 SkScalar textSize = paint.getTextSize();
Mike Reeda99b6ce2017-02-04 11:04:26 -05002721 SkScalar height = textSize * kStdUnderline_Thickness;
bungeman@google.com52c748b2011-08-22 21:30:43 +00002722 SkRect r;
2723
2724 r.fLeft = start.fX;
2725 r.fRight = start.fX + width;
2726
2727 if (flags & SkPaint::kUnderlineText_Flag) {
Mike Reeda99b6ce2017-02-04 11:04:26 -05002728 SkScalar offset = textSize * kStdUnderline_Offset + start.fY;
bungeman@google.com52c748b2011-08-22 21:30:43 +00002729 r.fTop = offset;
2730 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002731 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002732 }
2733 if (flags & SkPaint::kStrikeThruText_Flag) {
Mike Reeda99b6ce2017-02-04 11:04:26 -05002734 SkScalar offset = textSize * kStdStrikeThru_Offset + start.fY;
bungeman@google.com52c748b2011-08-22 21:30:43 +00002735 r.fTop = offset;
2736 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002737 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002738 }
2739 }
2740}
2741
reed@google.come0d9ce82014-04-23 04:00:17 +00002742void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2743 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002744 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002745
2746 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002747 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002748 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002749 DrawTextDecorations(iter, dfp.paint(),
2750 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751 }
2752
reed@google.com4e2b3d32011-04-07 14:18:59 +00002753 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002754}
2755
reed@google.come0d9ce82014-04-23 04:00:17 +00002756void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2757 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002758 SkPoint textOffset = SkPoint::Make(0, 0);
2759
halcanary96fcdcc2015-08-27 07:41:13 -07002760 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002761
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002763 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002764 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002765 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002767
reed@google.com4e2b3d32011-04-07 14:18:59 +00002768 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769}
2770
reed@google.come0d9ce82014-04-23 04:00:17 +00002771void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2772 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002773
2774 SkPoint textOffset = SkPoint::Make(0, constY);
2775
halcanary96fcdcc2015-08-27 07:41:13 -07002776 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002777
reed@android.com8a1c16f2008-12-17 15:59:43 +00002778 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002779 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002780 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002781 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002783
reed@google.com4e2b3d32011-04-07 14:18:59 +00002784 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002785}
2786
reed@google.come0d9ce82014-04-23 04:00:17 +00002787void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2788 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002789 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002790
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791 while (iter.next()) {
2792 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002793 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002794 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002795
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002796 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002797}
2798
reed45561a02016-07-07 12:47:17 -07002799void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2800 const SkRect* cullRect, const SkPaint& paint) {
2801 if (cullRect && this->quickReject(*cullRect)) {
2802 return;
2803 }
2804
2805 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2806
2807 while (iter.next()) {
2808 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2809 }
2810
2811 LOOPER_END
2812}
2813
fmalita00d5c2c2014-08-21 08:53:26 -07002814void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2815 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002816
fmalita85d5eb92015-03-04 11:20:12 -08002817 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002818 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002819 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002820 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002821 SkRect tmp;
2822 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2823 return;
2824 }
2825 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002826 }
2827
fmalita024f9962015-03-03 19:08:17 -08002828 // We cannot filter in the looper as we normally do, because the paint is
2829 // incomplete at this point (text-related attributes are embedded within blob run paints).
2830 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002831 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002832
fmalita85d5eb92015-03-04 11:20:12 -08002833 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002834
fmalitaaa1b9122014-08-28 14:32:24 -07002835 while (iter.next()) {
2836 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002837 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002838 }
2839
fmalitaaa1b9122014-08-28 14:32:24 -07002840 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002841
2842 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002843}
2844
reed@google.come0d9ce82014-04-23 04:00:17 +00002845// These will become non-virtual, so they always call the (virtual) onDraw... method
2846void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2847 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002848 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002849 if (byteLength) {
2850 this->onDrawText(text, byteLength, x, y, paint);
2851 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002852}
2853void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2854 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002855 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002856 if (byteLength) {
2857 this->onDrawPosText(text, byteLength, pos, paint);
2858 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002859}
2860void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2861 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002862 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002863 if (byteLength) {
2864 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2865 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002866}
2867void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2868 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002869 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002870 if (byteLength) {
2871 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2872 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002873}
reed45561a02016-07-07 12:47:17 -07002874void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2875 const SkRect* cullRect, const SkPaint& paint) {
2876 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2877 if (byteLength) {
2878 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2879 }
2880}
fmalita00d5c2c2014-08-21 08:53:26 -07002881void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2882 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002883 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002884 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002885 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002886}
reed@google.come0d9ce82014-04-23 04:00:17 +00002887
reed41af9662015-01-05 07:49:08 -08002888void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2889 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002890 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002891 const uint16_t indices[], int indexCount,
2892 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002893 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002894 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002895
reed@android.com8a1c16f2008-12-17 15:59:43 +00002896 while (iter.next()) {
2897 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002898 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002899 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002900 }
reed@google.com4b226022011-01-11 18:32:13 +00002901
reed@google.com4e2b3d32011-04-07 14:18:59 +00002902 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002903}
2904
Brian Salomon199fb872017-02-06 09:41:10 -05002905void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode,
2906 const SkPaint& paint, uint32_t flags) {
2907 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2908 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2909
2910 while (iter.next()) {
2911 // In the common case of one iteration we could std::move vertices here.
2912 iter.fDevice->drawVerticesObject(iter, vertices, bmode, looper.paint(), flags);
2913 }
2914
2915 LOOPER_END
2916}
2917
2918void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode,
2919 const SkPaint& paint, uint32_t flags) {
2920 const SkPoint* texs =
2921 (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords();
2922 const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors();
2923 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs,
2924 colors, mode, vertices->indices(), vertices->indexCount(), paint);
2925}
2926
dandovb3c9d1c2014-08-12 08:34:29 -07002927void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002928 const SkPoint texCoords[4], SkBlendMode bmode,
2929 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002930 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002931 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002932 return;
2933 }
mtklein6cfa73a2014-08-13 13:33:49 -07002934
Mike Reedfaba3712016-11-03 14:45:31 -04002935 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002936}
2937
2938void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002939 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002940 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002941 // Since a patch is always within the convex hull of the control points, we discard it when its
2942 // bounding rectangle is completely outside the current clip.
2943 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002944 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002945 if (this->quickReject(bounds)) {
2946 return;
2947 }
mtklein6cfa73a2014-08-13 13:33:49 -07002948
halcanary96fcdcc2015-08-27 07:41:13 -07002949 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002950
dandovecfff212014-08-04 10:02:00 -07002951 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002952 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002953 }
mtklein6cfa73a2014-08-13 13:33:49 -07002954
dandovecfff212014-08-04 10:02:00 -07002955 LOOPER_END
2956}
2957
reeda8db7282015-07-07 10:22:31 -07002958void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002959 RETURN_ON_NULL(dr);
2960 if (x || y) {
2961 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2962 this->onDrawDrawable(dr, &matrix);
2963 } else {
2964 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002965 }
2966}
2967
reeda8db7282015-07-07 10:22:31 -07002968void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002969 RETURN_ON_NULL(dr);
2970 if (matrix && matrix->isIdentity()) {
2971 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002972 }
reede3b38ce2016-01-08 09:18:44 -08002973 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002974}
2975
2976void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002977 // drawable bounds are no longer reliable (e.g. android displaylist)
2978 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002979 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002980}
2981
reed71c3c762015-06-24 10:29:17 -07002982void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002983 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002984 const SkRect* cull, const SkPaint* paint) {
2985 if (cull && this->quickReject(*cull)) {
2986 return;
2987 }
2988
2989 SkPaint pnt;
2990 if (paint) {
2991 pnt = *paint;
2992 }
halcanary9d524f22016-03-29 09:03:52 -07002993
halcanary96fcdcc2015-08-27 07:41:13 -07002994 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002995 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002996 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002997 }
2998 LOOPER_END
2999}
3000
reedf70b5312016-03-04 16:36:20 -08003001void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
3002 SkASSERT(key);
3003
3004 SkPaint paint;
3005 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
3006 while (iter.next()) {
3007 iter.fDevice->drawAnnotation(iter, rect, key, value);
3008 }
3009 LOOPER_END
3010}
3011
reed@android.com8a1c16f2008-12-17 15:59:43 +00003012//////////////////////////////////////////////////////////////////////////////
3013// These methods are NOT virtual, and therefore must call back into virtual
3014// methods, rather than actually drawing themselves.
3015//////////////////////////////////////////////////////////////////////////////
3016
reed374772b2016-10-05 17:33:02 -07003017void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08003018 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003019 SkPaint paint;
3020
3021 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07003022 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003023 this->drawPaint(paint);
3024}
3025
reed374772b2016-10-05 17:33:02 -07003026void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08003027 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003028 SkPaint paint;
3029
3030 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07003031 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003032 this->drawPaint(paint);
3033}
3034
3035void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003036 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003037 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00003038
reed@android.com8a1c16f2008-12-17 15:59:43 +00003039 pt.set(x, y);
3040 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3041}
3042
3043void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08003044 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003045 SkPoint pt;
3046 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00003047
reed@android.com8a1c16f2008-12-17 15:59:43 +00003048 pt.set(x, y);
3049 paint.setColor(color);
3050 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3051}
3052
3053void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
3054 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003055 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003056 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003057
reed@android.com8a1c16f2008-12-17 15:59:43 +00003058 pts[0].set(x0, y0);
3059 pts[1].set(x1, y1);
3060 this->drawPoints(kLines_PointMode, 2, pts, paint);
3061}
3062
3063void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3064 SkScalar right, SkScalar bottom,
3065 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003066 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003067 SkRect r;
3068
3069 r.set(left, top, right, bottom);
3070 this->drawRect(r, paint);
3071}
3072
3073void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3074 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003075 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003076 if (radius < 0) {
3077 radius = 0;
3078 }
3079
3080 SkRect r;
3081 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003082 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003083}
3084
3085void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3086 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003087 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003088 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003089 SkRRect rrect;
3090 rrect.setRectXY(r, rx, ry);
3091 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003092 } else {
3093 this->drawRect(r, paint);
3094 }
3095}
3096
reed@android.com8a1c16f2008-12-17 15:59:43 +00003097void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3098 SkScalar sweepAngle, bool useCenter,
3099 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003100 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003101 if (oval.isEmpty() || !sweepAngle) {
3102 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003103 }
bsalomon21af9ca2016-08-25 12:29:23 -07003104 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003105}
3106
3107void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3108 const SkPath& path, SkScalar hOffset,
3109 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003110 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003111 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003112
reed@android.com8a1c16f2008-12-17 15:59:43 +00003113 matrix.setTranslate(hOffset, vOffset);
3114 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3115}
3116
reed@android.comf76bacf2009-05-13 14:00:33 +00003117///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003118
3119/**
3120 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3121 * against the playback cost of recursing into the subpicture to get at its actual ops.
3122 *
3123 * For now we pick a conservatively small value, though measurement (and other heuristics like
3124 * the type of ops contained) may justify changing this value.
3125 */
3126#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003127
reedd5fa1a42014-08-09 11:08:05 -07003128void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003129 RETURN_ON_NULL(picture);
3130
reed1c2c4412015-04-30 13:09:24 -07003131 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003132 if (matrix && matrix->isIdentity()) {
3133 matrix = nullptr;
3134 }
3135 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3136 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3137 picture->playback(this);
3138 } else {
3139 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003140 }
3141}
robertphillips9b14f262014-06-04 05:40:44 -07003142
reedd5fa1a42014-08-09 11:08:05 -07003143void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3144 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003145 if (!paint || paint->canComputeFastBounds()) {
3146 SkRect bounds = picture->cullRect();
3147 if (paint) {
3148 paint->computeFastBounds(bounds, &bounds);
3149 }
3150 if (matrix) {
3151 matrix->mapRect(&bounds);
3152 }
3153 if (this->quickReject(bounds)) {
3154 return;
3155 }
3156 }
3157
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003158 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003159 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003160}
3161
vjiaoblack95302da2016-07-21 10:25:54 -07003162#ifdef SK_EXPERIMENTAL_SHADOWING
3163void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3164 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003165 const SkPaint* paint,
3166 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003167 RETURN_ON_NULL(picture);
3168
3169 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3170
vjiaoblacke6f5d562016-08-25 06:30:23 -07003171 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003172}
3173
3174void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3175 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003176 const SkPaint* paint,
3177 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003178 if (!paint || paint->canComputeFastBounds()) {
3179 SkRect bounds = picture->cullRect();
3180 if (paint) {
3181 paint->computeFastBounds(bounds, &bounds);
3182 }
3183 if (matrix) {
3184 matrix->mapRect(&bounds);
3185 }
3186 if (this->quickReject(bounds)) {
3187 return;
3188 }
3189 }
3190
3191 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3192
vjiaoblacke6f5d562016-08-25 06:30:23 -07003193 sk_sp<SkImage> povDepthMap;
3194 sk_sp<SkImage> diffuseMap;
3195
vjiaoblack904527d2016-08-09 09:32:09 -07003196 // povDepthMap
3197 {
3198 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003199 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3200 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003201 sk_sp<SkLights> povLight = builder.finish();
3202
3203 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3204 picture->cullRect().height(),
3205 kBGRA_8888_SkColorType,
3206 kOpaque_SkAlphaType);
3207
3208 // Create a new surface (that matches the backend of canvas)
3209 // to create the povDepthMap
3210 sk_sp<SkSurface> surf(this->makeSurface(info));
3211
3212 // Wrap another SPFCanvas around the surface
3213 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3214 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3215
3216 // set the depth map canvas to have the light as the user's POV
3217 depthMapCanvas->setLights(std::move(povLight));
3218
3219 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003220 povDepthMap = surf->makeImageSnapshot();
3221 }
3222
3223 // diffuseMap
3224 {
3225 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3226 picture->cullRect().height(),
3227 kBGRA_8888_SkColorType,
3228 kOpaque_SkAlphaType);
3229
3230 sk_sp<SkSurface> surf(this->makeSurface(info));
3231 surf->getCanvas()->drawPicture(picture);
3232
3233 diffuseMap = surf->makeImageSnapshot();
3234 }
vjiaoblack904527d2016-08-09 09:32:09 -07003235
3236 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3237 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003238 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3239 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003240
3241 // TODO: pass the depth to the shader in vertices, or uniforms
3242 // so we don't have to render depth and color separately
3243 for (int i = 0; i < fLights->numLights(); ++i) {
3244 // skip over ambient lights; they don't cast shadows
3245 // lights that have shadow maps do not need updating (because lights are immutable)
3246 sk_sp<SkImage> depthMap;
3247 SkISize shMapSize;
3248
3249 if (fLights->light(i).getShadowMap() != nullptr) {
3250 continue;
3251 }
3252
3253 if (fLights->light(i).isRadial()) {
3254 shMapSize.fHeight = 1;
3255 shMapSize.fWidth = (int) picture->cullRect().width();
3256
3257 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3258 kBGRA_8888_SkColorType,
3259 kOpaque_SkAlphaType);
3260
3261 // Create new surface (that matches the backend of canvas)
3262 // for each shadow map
3263 sk_sp<SkSurface> surf(this->makeSurface(info));
3264
3265 // Wrap another SPFCanvas around the surface
3266 SkCanvas* depthMapCanvas = surf->getCanvas();
3267
3268 SkLights::Builder builder;
3269 builder.add(fLights->light(i));
3270 sk_sp<SkLights> curLight = builder.finish();
3271
3272 sk_sp<SkShader> shadowMapShader;
3273 shadowMapShader = SkRadialShadowMapShader::Make(
3274 povDepthShader, curLight,
3275 (int) picture->cullRect().width(),
3276 (int) picture->cullRect().height());
3277
3278 SkPaint shadowMapPaint;
3279 shadowMapPaint.setShader(std::move(shadowMapShader));
3280
3281 depthMapCanvas->setLights(curLight);
3282
3283 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3284 diffuseMap->height()),
3285 shadowMapPaint);
3286
3287 depthMap = surf->makeImageSnapshot();
3288
3289 } else {
3290 // TODO: compute the correct size of the depth map from the light properties
3291 // TODO: maybe add a kDepth_8_SkColorType
3292 // TODO: find actual max depth of picture
3293 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3294 fLights->light(i), 255,
3295 (int) picture->cullRect().width(),
3296 (int) picture->cullRect().height());
3297
3298 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3299 kBGRA_8888_SkColorType,
3300 kOpaque_SkAlphaType);
3301
3302 // Create a new surface (that matches the backend of canvas)
3303 // for each shadow map
3304 sk_sp<SkSurface> surf(this->makeSurface(info));
3305
3306 // Wrap another SPFCanvas around the surface
3307 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3308 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3309 depthMapCanvas->setShadowParams(params);
3310
3311 // set the depth map canvas to have the light we're drawing.
3312 SkLights::Builder builder;
3313 builder.add(fLights->light(i));
3314 sk_sp<SkLights> curLight = builder.finish();
3315 depthMapCanvas->setLights(std::move(curLight));
3316
3317 depthMapCanvas->drawPicture(picture);
3318 depthMap = surf->makeImageSnapshot();
3319 }
3320
3321 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3322 fLights->light(i).setShadowMap(std::move(depthMap));
3323 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3324 // we blur the variance map
3325 SkPaint blurPaint;
3326 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3327 params.fShadowRadius, nullptr));
3328
3329 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3330 kBGRA_8888_SkColorType,
3331 kOpaque_SkAlphaType);
3332
3333 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3334
3335 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3336
3337 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3338 }
3339 }
3340
3341 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003342 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3343 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003344 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003345 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003346 diffuseMap->height(),
3347 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003348
3349 shadowPaint.setShader(shadowShader);
3350
3351 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003352}
3353#endif
3354
reed@android.com8a1c16f2008-12-17 15:59:43 +00003355///////////////////////////////////////////////////////////////////////////////
3356///////////////////////////////////////////////////////////////////////////////
3357
reed3aafe112016-08-18 12:45:34 -07003358SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003359 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003360
3361 SkASSERT(canvas);
3362
reed3aafe112016-08-18 12:45:34 -07003363 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003364 fDone = !fImpl->next();
3365}
3366
3367SkCanvas::LayerIter::~LayerIter() {
3368 fImpl->~SkDrawIter();
3369}
3370
3371void SkCanvas::LayerIter::next() {
3372 fDone = !fImpl->next();
3373}
3374
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003375SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003376 return fImpl->getDevice();
3377}
3378
3379const SkMatrix& SkCanvas::LayerIter::matrix() const {
3380 return fImpl->getMatrix();
3381}
3382
3383const SkPaint& SkCanvas::LayerIter::paint() const {
3384 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003385 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003386 paint = &fDefaultPaint;
3387 }
3388 return *paint;
3389}
3390
reed1e7f5e72016-04-27 07:49:17 -07003391const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003392int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3393int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003394
3395///////////////////////////////////////////////////////////////////////////////
3396
fmalitac3b589a2014-06-05 12:40:07 -07003397SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003398
3399///////////////////////////////////////////////////////////////////////////////
3400
3401static bool supported_for_raster_canvas(const SkImageInfo& info) {
3402 switch (info.alphaType()) {
3403 case kPremul_SkAlphaType:
3404 case kOpaque_SkAlphaType:
3405 break;
3406 default:
3407 return false;
3408 }
3409
3410 switch (info.colorType()) {
3411 case kAlpha_8_SkColorType:
3412 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003413 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003414 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003415 break;
3416 default:
3417 return false;
3418 }
3419
3420 return true;
3421}
3422
Mike Reed5df49342016-11-12 08:06:55 -06003423std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3424 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003425 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003426 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003427 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003428
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003429 SkBitmap bitmap;
3430 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003431 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003432 }
Mike Reed5df49342016-11-12 08:06:55 -06003433 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003434}
reedd5fa1a42014-08-09 11:08:05 -07003435
3436///////////////////////////////////////////////////////////////////////////////
3437
3438SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003439 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003440 : fCanvas(canvas)
3441 , fSaveCount(canvas->getSaveCount())
3442{
bsalomon49f085d2014-09-05 13:34:00 -07003443 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003444 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003445 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003446 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003447 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003448 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003449 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003450 canvas->save();
3451 }
mtklein6cfa73a2014-08-13 13:33:49 -07003452
bsalomon49f085d2014-09-05 13:34:00 -07003453 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003454 canvas->concat(*matrix);
3455 }
3456}
3457
3458SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3459 fCanvas->restoreToCount(fSaveCount);
3460}
reede8f30622016-03-23 18:59:25 -07003461
Florin Malitaee424ac2016-12-01 12:47:59 -05003462///////////////////////////////////////////////////////////////////////////////
3463
3464SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3465 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3466
Florin Malita439ace92016-12-02 12:05:41 -05003467SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3468 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3469
Florin Malitaee424ac2016-12-01 12:47:59 -05003470SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3471 (void)this->INHERITED::getSaveLayerStrategy(rec);
3472 return kNoLayer_SaveLayerStrategy;
3473}
3474
3475///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003476
reed73603f32016-09-20 08:42:38 -07003477static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3478static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3479static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3480static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3481static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3482static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003483
3484///////////////////////////////////////////////////////////////////////////////////////////////////
3485
3486SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3487 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3488 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3489 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3490 SkIPoint origin = dev->getOrigin();
3491 SkMatrix ctm = this->getTotalMatrix();
3492 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3493
3494 SkIRect clip = fMCRec->fRasterClip.getBounds();
3495 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003496 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003497 clip.setEmpty();
3498 }
3499
3500 fAllocator->updateHandle(handle, ctm, clip);
3501 return handle;
3502 }
3503 return nullptr;
3504}
3505
3506static bool install(SkBitmap* bm, const SkImageInfo& info,
3507 const SkRasterHandleAllocator::Rec& rec) {
3508 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3509 rec.fReleaseProc, rec.fReleaseCtx);
3510}
3511
3512SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3513 SkBitmap* bm) {
3514 SkRasterHandleAllocator::Rec rec;
3515 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3516 return nullptr;
3517 }
3518 return rec.fHandle;
3519}
3520
3521std::unique_ptr<SkCanvas>
3522SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3523 const SkImageInfo& info, const Rec* rec) {
3524 if (!alloc || !supported_for_raster_canvas(info)) {
3525 return nullptr;
3526 }
3527
3528 SkBitmap bm;
3529 Handle hndl;
3530
3531 if (rec) {
3532 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3533 } else {
3534 hndl = alloc->allocBitmap(info, &bm);
3535 }
3536 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3537}