blob: 04cead44fb7eba411ea85182992d2524d949bc70 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060023#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080024#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000025#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050026#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070027#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070028#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070029#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000030#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070031#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000032#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050033#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070035#include "SkShadowPaintFilterCanvas.h"
36#include "SkShadowShader.h"
robertphillips4418dba2016-03-07 12:45:14 -080037#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000038#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070039#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000040#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000041#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080042#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070043#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080046#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000047#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070048#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050051#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050052#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053
reede3b38ce2016-01-08 09:18:44 -080054#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
55
reedc83a2972015-07-16 07:40:45 -070056/*
57 * Return true if the drawing this rect would hit every pixels in the canvas.
58 *
59 * Returns false if
60 * - rect does not contain the canvas' bounds
61 * - paint is not fill
62 * - paint would blur or otherwise change the coverage of the rect
63 */
64bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
65 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070066 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
67 (int)kNone_ShaderOverrideOpacity,
68 "need_matching_enums0");
69 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
70 (int)kOpaque_ShaderOverrideOpacity,
71 "need_matching_enums1");
72 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
73 (int)kNotOpaque_ShaderOverrideOpacity,
74 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070075
76 const SkISize size = this->getBaseLayerSize();
77 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
78 if (!this->getClipStack()->quickContains(bounds)) {
79 return false;
80 }
81
82 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070083 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070084 return false; // conservative
85 }
halcanaryc5769b22016-08-10 07:13:21 -070086
87 SkRect devRect;
88 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
89 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070090 return false;
91 }
92 }
93
94 if (paint) {
95 SkPaint::Style paintStyle = paint->getStyle();
96 if (!(paintStyle == SkPaint::kFill_Style ||
97 paintStyle == SkPaint::kStrokeAndFill_Style)) {
98 return false;
99 }
100 if (paint->getMaskFilter() || paint->getLooper()
101 || paint->getPathEffect() || paint->getImageFilter()) {
102 return false; // conservative
103 }
104 }
105 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
106}
107
108///////////////////////////////////////////////////////////////////////////////////////////////////
109
reedd990e2f2014-12-22 11:58:30 -0800110static bool gIgnoreSaveLayerBounds;
111void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
112 gIgnoreSaveLayerBounds = ignore;
113}
114bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
115 return gIgnoreSaveLayerBounds;
116}
117
reed0acf1b42014-12-22 16:12:38 -0800118static bool gTreatSpriteAsBitmap;
119void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
120 gTreatSpriteAsBitmap = spriteAsBitmap;
121}
122bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
123 return gTreatSpriteAsBitmap;
124}
125
reed@google.comda17f752012-08-16 18:27:05 +0000126// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127//#define SK_TRACE_SAVERESTORE
128
129#ifdef SK_TRACE_SAVERESTORE
130 static int gLayerCounter;
131 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
132 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
133
134 static int gRecCounter;
135 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
136 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
137
138 static int gCanvasCounter;
139 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
140 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
141#else
142 #define inc_layer()
143 #define dec_layer()
144 #define inc_rec()
145 #define dec_rec()
146 #define inc_canvas()
147 #define dec_canvas()
148#endif
149
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000150typedef SkTLazy<SkPaint> SkLazyPaint;
151
reedc83a2972015-07-16 07:40:45 -0700152void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000153 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700154 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
155 ? SkSurface::kDiscard_ContentChangeMode
156 : SkSurface::kRetain_ContentChangeMode);
157 }
158}
159
160void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
161 ShaderOverrideOpacity overrideOpacity) {
162 if (fSurfaceBase) {
163 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
164 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
165 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
166 // and therefore we don't care which mode we're in.
167 //
168 if (fSurfaceBase->outstandingImageSnapshot()) {
169 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
170 mode = SkSurface::kDiscard_ContentChangeMode;
171 }
172 }
173 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000174 }
175}
176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000179/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 The clip/matrix/proc are fields that reflect the top of the save/restore
181 stack. Whenever the canvas changes, it marks a dirty flag, and then before
182 these are used (assuming we're not on a layer) we rebuild these cache
183 values: they reflect the top of the save stack, but translated and clipped
184 by the device's XY offset and bitmap-bounds.
185*/
186struct DeviceCM {
187 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000188 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000189 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000190 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700191 const SkMatrix* fMatrix;
192 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700193 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194
reed96e657d2015-03-10 17:30:07 -0700195 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700196 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700197 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700198 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700199 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700200 {
reed2c9e2002016-07-25 08:05:22 -0700201 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000202 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700203 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000204 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000206 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700207 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700208 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000209 }
reed@google.com4b226022011-01-11 18:32:13 +0000210
mtkleinfeaadee2015-04-08 11:25:48 -0700211 void reset(const SkIRect& bounds) {
212 SkASSERT(!fPaint);
213 SkASSERT(!fNext);
214 SkASSERT(fDevice);
215 fClip.setRect(bounds);
216 }
217
reed@google.com045e62d2011-10-24 12:19:46 +0000218 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700219 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000220 int x = fDevice->getOrigin().x();
221 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 int width = fDevice->width();
223 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000224
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 if ((x | y) == 0) {
226 fMatrix = &totalMatrix;
227 fClip = totalClip;
228 } else {
229 fMatrixStorage = totalMatrix;
230 fMatrixStorage.postTranslate(SkIntToScalar(-x),
231 SkIntToScalar(-y));
232 fMatrix = &fMatrixStorage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 totalClip.translate(-x, -y, &fClip);
234 }
235
reed@google.com045e62d2011-10-24 12:19:46 +0000236 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
Mike Reedc42a1cd2017-02-14 14:25:14 -0500238#ifdef SK_USE_DEVICE_CLIPPING
239 SkASSERT(*fMatrix == fDevice->ctm());
240 // TODO: debug tiles-rt-8888 so we can enable this all the time
241// fDevice->validateDevBounds(fClip.getBounds());
242#endif
243
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000247 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248 SkRegion::kDifference_Op);
249 }
reed@google.com4b226022011-01-11 18:32:13 +0000250
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251#ifdef SK_DEBUG
252 if (!fClip.isEmpty()) {
253 SkIRect deviceR;
254 deviceR.set(0, 0, width, height);
255 SkASSERT(deviceR.contains(fClip.getBounds()));
256 }
257#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000258 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259};
260
261/* This is the record we keep for each save/restore level in the stack.
262 Since a level optionally copies the matrix and/or stack, we have pointers
263 for these fields. If the value is copied for this level, the copy is
264 stored in the ...Storage field, and the pointer points to that. If the
265 value is not copied for this level, we ignore ...Storage, and just point
266 at the corresponding value in the previous level in the stack.
267*/
268class SkCanvas::MCRec {
269public:
reed1f836ee2014-07-07 07:49:34 -0700270 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700271 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 /* If there are any layers in the stack, this points to the top-most
273 one that is at or below this level in the stack (so we know what
274 bitmap/device to draw into from this level. This value is NOT
275 reference counted, since the real owner is either our fLayer field,
276 or a previous one in a lower level.)
277 */
reed2ff1fce2014-12-11 07:07:37 -0800278 DeviceCM* fTopLayer;
279 SkRasterClip fRasterClip;
280 SkMatrix fMatrix;
281 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282
vjiaoblacke5de1302016-07-13 14:05:28 -0700283 // This is the current cumulative depth (aggregate of all done translateZ calls)
284 SkScalar fCurDrawDepth;
285
reedd9544982014-09-09 18:46:22 -0700286 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700287 fFilter = nullptr;
288 fLayer = nullptr;
289 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800290 fMatrix.reset();
291 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700292 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700293
reedd9544982014-09-09 18:46:22 -0700294 // don't bother initializing fNext
295 inc_rec();
296 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700297 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
298 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700299 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700300 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700301 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800302 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700303
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 // don't bother initializing fNext
305 inc_rec();
306 }
307 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000308 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700309 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310 dec_rec();
311 }
mtkleinfeaadee2015-04-08 11:25:48 -0700312
313 void reset(const SkIRect& bounds) {
314 SkASSERT(fLayer);
315 SkASSERT(fDeferredSaveCount == 0);
316
317 fMatrix.reset();
318 fRasterClip.setRect(bounds);
319 fLayer->reset(bounds);
320 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321};
322
reed02f9ed72016-09-06 09:06:18 -0700323static SkIRect compute_device_bounds(SkBaseDevice* device) {
324 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
325 device->width(), device->height());
326}
327
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328class SkDrawIter : public SkDraw {
329public:
Mike Reed99330ba2017-02-22 11:01:08 -0500330 SkDrawIter(SkCanvas* canvas) : fDevice(nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 canvas->updateDeviceCMCache();
332
bungeman6bd52842016-10-27 09:30:08 -0700333 fClipStack = canvas->getClipStack();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700335
336 fMultiDeviceCS = nullptr;
337 if (fCurrLayer->fNext) {
bungeman6bd52842016-10-27 09:30:08 -0700338 fMultiDeviceCS = canvas->fClipStack.get();
reed02f9ed72016-09-06 09:06:18 -0700339 fMultiDeviceCS->save();
340 }
Mike Reedd519d482017-02-16 11:04:52 -0500341#ifdef SK_USE_DEVICE_CLIPPING
342 fClipStack = nullptr; // for testing
343#endif
reed02f9ed72016-09-06 09:06:18 -0700344 }
345
346 ~SkDrawIter() {
347 if (fMultiDeviceCS) {
348 fMultiDeviceCS->restore();
349 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 }
reed@google.com4b226022011-01-11 18:32:13 +0000351
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700353 if (fMultiDeviceCS && fDevice) {
354 // remove the previous device's bounds
Mike Reedc1f77742016-12-09 09:00:50 -0500355 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), kDifference_SkClipOp);
reed02f9ed72016-09-06 09:06:18 -0700356 }
357
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700359 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
360 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 }
362
reed@google.comf68c5e22012-02-24 16:38:58 +0000363 const DeviceCM* rec = fCurrLayer;
364 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365
366 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000367 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700369 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700370 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700371 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000373 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374
375 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700376 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000377
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 return true;
379 }
380 return false;
381 }
reed@google.com4b226022011-01-11 18:32:13 +0000382
reed1e7f5e72016-04-27 07:49:17 -0700383 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000384 int getX() const { return fDevice->getOrigin().x(); }
385 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000386 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000387 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000388
Mike Reed99330ba2017-02-22 11:01:08 -0500389 SkBaseDevice* fDevice;
390
reed@android.com8a1c16f2008-12-17 15:59:43 +0000391private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392 const DeviceCM* fCurrLayer;
393 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700394 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000395
396 typedef SkDraw INHERITED;
397};
398
Mike Reed7627fa52017-02-08 10:07:53 -0500399#define FOR_EACH_TOP_DEVICE( code ) \
400 do { \
401 DeviceCM* layer = fMCRec->fTopLayer; \
402 while (layer) { \
403 SkBaseDevice* device = layer->fDevice; \
Mike Reedc42a1cd2017-02-14 14:25:14 -0500404 if (device) { \
405 code; \
406 } \
Mike Reed7627fa52017-02-08 10:07:53 -0500407 layer = layer->fNext; \
408 } \
409 } while (0)
410
reed@android.com8a1c16f2008-12-17 15:59:43 +0000411/////////////////////////////////////////////////////////////////////////////
412
reeddbc3cef2015-04-29 12:18:57 -0700413static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
414 return lazy->isValid() ? lazy->get() : lazy->set(orig);
415}
416
417/**
418 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700419 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700420 */
reedd053ce92016-03-22 10:17:23 -0700421static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700422 SkImageFilter* imgf = paint.getImageFilter();
423 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700424 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700425 }
426
reedd053ce92016-03-22 10:17:23 -0700427 SkColorFilter* imgCFPtr;
428 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700429 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700430 }
reedd053ce92016-03-22 10:17:23 -0700431 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700432
433 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700434 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700435 // there is no existing paint colorfilter, so we can just return the imagefilter's
436 return imgCF;
437 }
438
439 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
440 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700441 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700442}
443
senorblanco87e066e2015-10-28 11:23:36 -0700444/**
445 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
446 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
447 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
448 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
449 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
450 * conservative "effective" bounds based on the settings in the paint... with one exception. This
451 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
452 * deliberately ignored.
453 */
454static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
455 const SkRect& rawBounds,
456 SkRect* storage) {
457 SkPaint tmpUnfiltered(paint);
458 tmpUnfiltered.setImageFilter(nullptr);
459 if (tmpUnfiltered.canComputeFastBounds()) {
460 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
461 } else {
462 return rawBounds;
463 }
464}
465
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466class AutoDrawLooper {
467public:
senorblanco87e066e2015-10-28 11:23:36 -0700468 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
469 // paint. It's used to determine the size of the offscreen layer for filters.
470 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700471 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700472 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000473 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800474#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000475 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800476#else
477 fFilter = nullptr;
478#endif
reed4a8126e2014-09-22 07:29:03 -0700479 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000480 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700481 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000482 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000483
reedd053ce92016-03-22 10:17:23 -0700484 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700485 if (simplifiedCF) {
486 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700487 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700488 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700489 fPaint = paint;
490 }
491
492 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700493 /**
494 * We implement ImageFilters for a given draw by creating a layer, then applying the
495 * imagefilter to the pixels of that layer (its backing surface/image), and then
496 * we call restore() to xfer that layer to the main canvas.
497 *
498 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
499 * 2. Generate the src pixels:
500 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
501 * return (fPaint). We then draw the primitive (using srcover) into a cleared
502 * buffer/surface.
503 * 3. Restore the layer created in #1
504 * The imagefilter is passed the buffer/surface from the layer (now filled with the
505 * src pixels of the primitive). It returns a new "filtered" buffer, which we
506 * draw onto the previous layer using the xfermode from the original paint.
507 */
reed@google.com8926b162012-03-23 15:36:36 +0000508 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500509 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700510 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700511 SkRect storage;
512 if (rawBounds) {
513 // Make rawBounds include all paint outsets except for those due to image filters.
514 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
515 }
reedbfd5f172016-01-07 11:28:08 -0800516 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700517 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700518 fTempLayerForImageFilter = true;
519 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000520 }
521
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000522 if (SkDrawLooper* looper = paint.getLooper()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500523 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000524 fIsSimple = false;
525 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700526 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000527 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700528 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000529 }
530 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000531
reed@android.com8a1c16f2008-12-17 15:59:43 +0000532 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700533 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000534 fCanvas->internalRestore();
535 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000536 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000537 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000538
reed@google.com4e2b3d32011-04-07 14:18:59 +0000539 const SkPaint& paint() const {
540 SkASSERT(fPaint);
541 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000542 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000543
reed@google.com129ec222012-05-15 13:24:09 +0000544 bool next(SkDrawFilter::Type drawType) {
545 if (fDone) {
546 return false;
547 } else if (fIsSimple) {
548 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000549 return !fPaint->nothingToDraw();
550 } else {
551 return this->doNext(drawType);
552 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000553 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000554
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500556 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700557 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000558 SkCanvas* fCanvas;
559 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000560 SkDrawFilter* fFilter;
561 const SkPaint* fPaint;
562 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700563 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000564 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000565 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000566 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500567 char fStorage[48];
568 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000569
570 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571};
572
reed@google.com129ec222012-05-15 13:24:09 +0000573bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700574 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000575 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700576 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000577
reeddbc3cef2015-04-29 12:18:57 -0700578 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
579 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000580
reed5c476fb2015-04-20 08:04:21 -0700581 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700582 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700583 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000584 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000585
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000586 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000587 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000588 return false;
589 }
590 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000591 if (!fFilter->filter(paint, drawType)) {
592 fDone = true;
593 return false;
594 }
halcanary96fcdcc2015-08-27 07:41:13 -0700595 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000596 // no looper means we only draw once
597 fDone = true;
598 }
599 }
600 fPaint = paint;
601
602 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000603 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000604 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000605 }
606
607 // call this after any possible paint modifiers
608 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700609 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000610 return false;
611 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000612 return true;
613}
614
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615////////// macros to place around the internal draw calls //////////////////
616
reed3aafe112016-08-18 12:45:34 -0700617#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
618 this->predrawNotify(); \
619 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
620 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800621 SkDrawIter iter(this);
622
623
reed@google.com8926b162012-03-23 15:36:36 +0000624#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000625 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700626 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000627 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000628 SkDrawIter iter(this);
629
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000630#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000631 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700632 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000633 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000634 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000635
reedc83a2972015-07-16 07:40:45 -0700636#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
637 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700638 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700639 while (looper.next(type)) { \
640 SkDrawIter iter(this);
641
reed@google.com4e2b3d32011-04-07 14:18:59 +0000642#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643
644////////////////////////////////////////////////////////////////////////////
645
msarettfbfa2582016-08-12 08:29:08 -0700646static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
647 if (bounds.isEmpty()) {
648 return SkRect::MakeEmpty();
649 }
650
651 // Expand bounds out by 1 in case we are anti-aliasing. We store the
652 // bounds as floats to enable a faster quick reject implementation.
653 SkRect dst;
654 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
655 return dst;
656}
657
mtkleinfeaadee2015-04-08 11:25:48 -0700658void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
659 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700660 fClipStack->reset();
661 fMCRec->reset(bounds);
662
663 // We're peering through a lot of structs here. Only at this scope do we
664 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
665 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700666 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700667 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700668}
669
reedd9544982014-09-09 18:46:22 -0700670SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800671 if (device && device->forceConservativeRasterClip()) {
672 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
673 }
674 // Since init() is only called once by our constructors, it is safe to perform this
675 // const-cast.
676 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
677
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000678 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700679 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800680 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700681 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700682#ifdef SK_EXPERIMENTAL_SHADOWING
683 fLights = nullptr;
684#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000685
halcanary385fe4d2015-08-26 13:07:48 -0700686 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700687
reed@android.com8a1c16f2008-12-17 15:59:43 +0000688 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700689 new (fMCRec) MCRec(fConservativeRasterClip);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500690 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700691 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692
reeda499f902015-05-01 09:34:31 -0700693 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
694 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700695 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700696 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700697
reed@android.com8a1c16f2008-12-17 15:59:43 +0000698 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699
halcanary96fcdcc2015-08-27 07:41:13 -0700700 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000701
reedf92c8662014-08-18 08:02:43 -0700702 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700703 // The root device and the canvas should always have the same pixel geometry
704 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700705 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800706 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700707 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
Mike Reedc42a1cd2017-02-14 14:25:14 -0500708
709#ifdef SK_USE_DEVICE_CLIPPING
710 device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
711#endif
reedf92c8662014-08-18 08:02:43 -0700712 }
msarettfbfa2582016-08-12 08:29:08 -0700713
reedf92c8662014-08-18 08:02:43 -0700714 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000715}
716
reed@google.comcde92112011-07-06 20:00:52 +0000717SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000718 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700719 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800720 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000721{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000722 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000723
halcanary96fcdcc2015-08-27 07:41:13 -0700724 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000725}
726
reedd9544982014-09-09 18:46:22 -0700727static SkBitmap make_nopixels(int width, int height) {
728 SkBitmap bitmap;
729 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
730 return bitmap;
731}
732
733class SkNoPixelsBitmapDevice : public SkBitmapDevice {
734public:
robertphillipsfcf78292015-06-19 11:49:52 -0700735 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
736 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800737 {
Mike Reedc42a1cd2017-02-14 14:25:14 -0500738 this->setOrigin(SkMatrix::I(), bounds.x(), bounds.y());
reed78e27682014-11-19 08:04:34 -0800739 }
reedd9544982014-09-09 18:46:22 -0700740
741private:
piotaixrb5fae932014-09-24 13:03:30 -0700742
reedd9544982014-09-09 18:46:22 -0700743 typedef SkBitmapDevice INHERITED;
744};
745
reed96a857e2015-01-25 10:33:58 -0800746SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000747 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800748 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800749 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000750{
751 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700752
halcanary385fe4d2015-08-26 13:07:48 -0700753 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
754 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700755}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000756
reed78e27682014-11-19 08:04:34 -0800757SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700758 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700759 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800760 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700761{
762 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700763
halcanary385fe4d2015-08-26 13:07:48 -0700764 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700765}
766
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000767SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000768 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700769 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800770 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000771{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700773
reedd9544982014-09-09 18:46:22 -0700774 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000775}
776
robertphillipsfcf78292015-06-19 11:49:52 -0700777SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
778 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700779 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800780 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700781{
782 inc_canvas();
783
784 this->init(device, flags);
785}
786
reed4a8126e2014-09-22 07:29:03 -0700787SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700788 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700789 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800790 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700791{
792 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700793
Hal Canary704cd322016-11-07 14:13:52 -0500794 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
795 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700796}
reed29c857d2014-09-21 10:25:07 -0700797
Mike Reed356f7c22017-01-10 11:58:39 -0500798SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
799 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700800 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
801 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500802 , fAllocator(std::move(alloc))
reed42b73eb2015-11-20 13:42:42 -0800803 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700804{
805 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700806
Mike Reed356f7c22017-01-10 11:58:39 -0500807 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500808 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809}
810
Mike Reed356f7c22017-01-10 11:58:39 -0500811SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
812
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813SkCanvas::~SkCanvas() {
814 // free up the contents of our deque
815 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000816
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817 this->internalRestore(); // restore the last, since we're going away
818
halcanary385fe4d2015-08-26 13:07:48 -0700819 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000820
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821 dec_canvas();
822}
823
fmalita53d9f1c2016-01-25 06:23:54 -0800824#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825SkDrawFilter* SkCanvas::getDrawFilter() const {
826 return fMCRec->fFilter;
827}
828
829SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700830 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
832 return filter;
833}
fmalita77650002016-01-21 18:47:11 -0800834#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000835
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000836SkMetaData& SkCanvas::getMetaData() {
837 // metadata users are rare, so we lazily allocate it. If that changes we
838 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700839 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000840 fMetaData = new SkMetaData;
841 }
842 return *fMetaData;
843}
844
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845///////////////////////////////////////////////////////////////////////////////
846
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000847void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700848 this->onFlush();
849}
850
851void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000852 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000853 if (device) {
854 device->flush();
855 }
856}
857
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000858SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000859 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000860 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
861}
862
senorblancoafc7cce2016-02-02 18:44:15 -0800863SkIRect SkCanvas::getTopLayerBounds() const {
864 SkBaseDevice* d = this->getTopDevice();
865 if (!d) {
866 return SkIRect::MakeEmpty();
867 }
868 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
869}
870
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000871SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000872 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000873 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000874 SkASSERT(rec && rec->fLayer);
875 return rec->fLayer->fDevice;
876}
877
Florin Malita0ed3b642017-01-13 16:56:38 +0000878SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000879 return fMCRec->fTopLayer->fDevice;
880}
881
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000882bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000883 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700884 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700885 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000886 return false;
887 }
888 weAllocated = true;
889 }
890
reedcf01e312015-05-23 19:14:51 -0700891 SkAutoPixmapUnlock unlocker;
892 if (bitmap->requestLock(&unlocker)) {
893 const SkPixmap& pm = unlocker.pixmap();
894 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
895 return true;
896 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000897 }
898
899 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500900 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000901 }
902 return false;
903}
reed@google.com51df9e32010-12-23 19:29:18 +0000904
bsalomon@google.comc6980972011-11-02 19:57:21 +0000905bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000906 SkIRect r = srcRect;
907 const SkISize size = this->getBaseLayerSize();
908 if (!r.intersect(0, 0, size.width(), size.height())) {
909 bitmap->reset();
910 return false;
911 }
912
reed84825042014-09-02 12:50:45 -0700913 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000914 // bitmap will already be reset.
915 return false;
916 }
917 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
918 bitmap->reset();
919 return false;
920 }
921 return true;
922}
923
reed96472de2014-12-10 09:53:42 -0800924bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000925 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000926 if (!device) {
927 return false;
928 }
mtkleinf0f14112014-12-12 08:46:25 -0800929
Matt Sarett03dd6d52017-01-23 12:15:09 -0500930 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000931}
932
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000933bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700934 SkAutoPixmapUnlock unlocker;
935 if (bitmap.requestLock(&unlocker)) {
936 const SkPixmap& pm = unlocker.pixmap();
937 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000938 }
939 return false;
940}
941
Matt Sarett03dd6d52017-01-23 12:15:09 -0500942bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000943 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000944 SkBaseDevice* device = this->getDevice();
945 if (!device) {
946 return false;
947 }
948
Matt Sarett03dd6d52017-01-23 12:15:09 -0500949 // This check gives us an early out and prevents generation ID churn on the surface.
950 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
951 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
952 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
953 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000954 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000955
Matt Sarett03dd6d52017-01-23 12:15:09 -0500956 // Tell our owning surface to bump its generation ID.
957 const bool completeOverwrite =
958 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700959 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700960
Matt Sarett03dd6d52017-01-23 12:15:09 -0500961 // This can still fail, most notably in the case of a invalid color type or alpha type
962 // conversion. We could pull those checks into this function and avoid the unnecessary
963 // generation ID bump. But then we would be performing those checks twice, since they
964 // are also necessary at the bitmap/pixmap entry points.
965 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000966}
reed@google.com51df9e32010-12-23 19:29:18 +0000967
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968//////////////////////////////////////////////////////////////////////////////
969
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970void SkCanvas::updateDeviceCMCache() {
971 if (fDeviceCMDirty) {
972 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700973 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000975
halcanary96fcdcc2015-08-27 07:41:13 -0700976 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700977 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000979 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980 do {
reedde6c5312016-09-02 12:10:07 -0700981 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700982 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000983 }
984 fDeviceCMDirty = false;
985 }
986}
987
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988///////////////////////////////////////////////////////////////////////////////
989
reed2ff1fce2014-12-11 07:07:37 -0800990void SkCanvas::checkForDeferredSave() {
991 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800992 this->doSave();
993 }
994}
995
reedf0090cb2014-11-26 08:55:51 -0800996int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800997#ifdef SK_DEBUG
998 int count = 0;
999 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1000 for (;;) {
1001 const MCRec* rec = (const MCRec*)iter.next();
1002 if (!rec) {
1003 break;
1004 }
1005 count += 1 + rec->fDeferredSaveCount;
1006 }
1007 SkASSERT(count == fSaveCount);
1008#endif
1009 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001010}
1011
1012int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001013 fSaveCount += 1;
1014 fMCRec->fDeferredSaveCount += 1;
1015 return this->getSaveCount() - 1; // return our prev value
1016}
1017
1018void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001019 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001020
1021 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1022 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001023 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001024}
1025
1026void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001027 if (fMCRec->fDeferredSaveCount > 0) {
1028 SkASSERT(fSaveCount > 1);
1029 fSaveCount -= 1;
1030 fMCRec->fDeferredSaveCount -= 1;
1031 } else {
1032 // check for underflow
1033 if (fMCStack.count() > 1) {
1034 this->willRestore();
1035 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001036 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001037 this->internalRestore();
1038 this->didRestore();
1039 }
reedf0090cb2014-11-26 08:55:51 -08001040 }
1041}
1042
1043void SkCanvas::restoreToCount(int count) {
1044 // sanity check
1045 if (count < 1) {
1046 count = 1;
1047 }
mtkleinf0f14112014-12-12 08:46:25 -08001048
reedf0090cb2014-11-26 08:55:51 -08001049 int n = this->getSaveCount() - count;
1050 for (int i = 0; i < n; ++i) {
1051 this->restore();
1052 }
1053}
1054
reed2ff1fce2014-12-11 07:07:37 -08001055void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001057 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001059
reed687fa1c2015-04-07 08:00:56 -07001060 fClipStack->save();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001061#ifdef SK_USE_DEVICE_CLIPPING
1062 FOR_EACH_TOP_DEVICE(device->save());
1063#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064}
1065
reed4960eee2015-12-18 07:09:18 -08001066bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001067 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001068}
1069
reed4960eee2015-12-18 07:09:18 -08001070bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001071 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -05001072 SkIRect clipBounds = this->getDeviceClipBounds();
1073 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001074 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001075 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001076
reed96e657d2015-03-10 17:30:07 -07001077 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1078
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001079 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001080 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001081 if (bounds && !imageFilter->canComputeFastBounds()) {
1082 bounds = nullptr;
1083 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001084 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001085 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001086 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001088
reed96e657d2015-03-10 17:30:07 -07001089 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090 r.roundOut(&ir);
1091 // early exit if the layer's bounds are clipped out
1092 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001093 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001094 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001095 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001096 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001097 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098 }
1099 } else { // no user bounds, so just use the clip
1100 ir = clipBounds;
1101 }
reed180aec42015-03-11 10:39:04 -07001102 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001103
reed4960eee2015-12-18 07:09:18 -08001104 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001105 // Simplify the current clips since they will be applied properly during restore()
Mike Reedc1f77742016-12-09 09:00:50 -05001106 fClipStack->clipDevRect(ir, kReplace_SkClipOp);
reed180aec42015-03-11 10:39:04 -07001107 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001108 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001109 }
1110
1111 if (intersection) {
1112 *intersection = ir;
1113 }
1114 return true;
1115}
1116
reed4960eee2015-12-18 07:09:18 -08001117
reed4960eee2015-12-18 07:09:18 -08001118int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1119 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001120}
1121
reed70ee31b2015-12-10 13:44:45 -08001122int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001123 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1124}
1125
1126int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1127 SaveLayerRec rec(origRec);
1128 if (gIgnoreSaveLayerBounds) {
1129 rec.fBounds = nullptr;
1130 }
1131 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1132 fSaveCount += 1;
1133 this->internalSaveLayer(rec, strategy);
1134 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001135}
1136
reeda2217ef2016-07-20 06:04:34 -07001137void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
Mike Reedc42a1cd2017-02-14 14:25:14 -05001138 SkBaseDevice* dst, const SkIPoint& dstOrigin,
1139 const SkMatrix& ctm, const SkClipStack* clipStack) {
reeda2217ef2016-07-20 06:04:34 -07001140 SkDraw draw;
1141 SkRasterClip rc;
1142 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1143 if (!dst->accessPixels(&draw.fDst)) {
1144 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001145 }
reeda2217ef2016-07-20 06:04:34 -07001146 draw.fMatrix = &SkMatrix::I();
1147 draw.fRC = &rc;
1148 draw.fClipStack = clipStack;
robertphillips7354a4b2015-12-16 05:08:27 -08001149
1150 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001151 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001152
Mike Reedc42a1cd2017-02-14 14:25:14 -05001153 int x = src->getOrigin().x() - dstOrigin.x();
1154 int y = src->getOrigin().y() - dstOrigin.y();
reeda2217ef2016-07-20 06:04:34 -07001155 auto special = src->snapSpecial();
1156 if (special) {
1157 dst->drawSpecial(draw, special.get(), x, y, p);
1158 }
robertphillips7354a4b2015-12-16 05:08:27 -08001159}
reed70ee31b2015-12-10 13:44:45 -08001160
reed129ed1c2016-02-22 06:42:31 -08001161static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1162 const SkPaint* paint) {
1163 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1164 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001165 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001166 const bool hasImageFilter = paint && paint->getImageFilter();
1167
1168 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1169 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1170 // force to L32
1171 return SkImageInfo::MakeN32(w, h, alphaType);
1172 } else {
1173 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001174 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001175 }
1176}
1177
reed4960eee2015-12-18 07:09:18 -08001178void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1179 const SkRect* bounds = rec.fBounds;
1180 const SkPaint* paint = rec.fPaint;
1181 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1182
reed8c30a812016-04-20 16:36:51 -07001183 SkLazyPaint lazyP;
1184 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1185 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001186 SkMatrix remainder;
1187 SkSize scale;
1188 /*
1189 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1190 * but they do handle scaling. To accommodate this, we do the following:
1191 *
1192 * 1. Stash off the current CTM
1193 * 2. Decompose the CTM into SCALE and REMAINDER
1194 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1195 * contains the REMAINDER
1196 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1197 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1198 * of the original imagefilter, and draw that (via drawSprite)
1199 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1200 *
1201 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1202 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1203 */
reed96a04f32016-04-25 09:25:15 -07001204 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001205 stashedMatrix.decomposeScale(&scale, &remainder))
1206 {
1207 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1208 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1209 SkPaint* p = lazyP.set(*paint);
1210 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1211 SkFilterQuality::kLow_SkFilterQuality,
1212 sk_ref_sp(imageFilter)));
1213 imageFilter = p->getImageFilter();
1214 paint = p;
1215 }
reed8c30a812016-04-20 16:36:51 -07001216
junov@chromium.orga907ac32012-02-24 21:54:07 +00001217 // do this before we create the layer. We don't call the public save() since
1218 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001219 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001220
1221 fDeviceCMDirty = true;
1222
1223 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001224 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001225 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226 }
1227
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001228 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1229 // the clipRectBounds() call above?
1230 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001231 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001232 }
1233
reed4960eee2015-12-18 07:09:18 -08001234 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001235 SkPixelGeometry geo = fProps.pixelGeometry();
1236 if (paint) {
reed76033be2015-03-14 10:54:31 -07001237 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001238 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001239 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001240 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001241 }
1242 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001243
robertphillips5139e502016-07-19 05:10:40 -07001244 SkBaseDevice* priorDevice = this->getTopDevice();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001245 if (nullptr == priorDevice) { // Do we still need this check???
reedb2db8982014-11-13 12:41:02 -08001246 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001247 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001248 }
reedb2db8982014-11-13 12:41:02 -08001249
robertphillips5139e502016-07-19 05:10:40 -07001250 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001251 paint);
1252
Hal Canary704cd322016-11-07 14:13:52 -05001253 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001254 {
reed70ee31b2015-12-10 13:44:45 -08001255 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001256 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001257 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001258 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001259 preserveLCDText,
1260 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001261 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1262 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001263 return;
reed61f501f2015-04-29 08:34:00 -07001264 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001265 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001266#ifndef SK_USE_DEVICE_CLIPPING
1267 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1268#endif
robertphillips7354a4b2015-12-16 05:08:27 -08001269
Hal Canary704cd322016-11-07 14:13:52 -05001270 DeviceCM* layer =
1271 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272
Mike Reedb43a3e02017-02-11 10:18:58 -05001273 // only have a "next" if this new layer doesn't affect the clip (rare)
1274 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275 fMCRec->fLayer = layer;
1276 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001277
1278 if (rec.fBackdrop) {
Mike Reedc42a1cd2017-02-14 14:25:14 -05001279 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(), { ir.fLeft, ir.fTop },
reeda2217ef2016-07-20 06:04:34 -07001280 fMCRec->fMatrix, this->getClipStack());
1281 }
Mike Reedc42a1cd2017-02-14 14:25:14 -05001282
1283#ifdef SK_USE_DEVICE_CLIPPING
1284 newDevice->setOrigin(fMCRec->fMatrix, ir.fLeft, ir.fTop);
1285
1286 newDevice->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
1287 if (layer->fNext) {
1288 // need to punch a hole in the previous device, so we don't draw there, given that
1289 // the new top-layer will allow drawing to happen "below" it.
1290 SkRegion hole(ir);
1291 do {
1292 layer = layer->fNext;
1293 layer->fDevice->clipRegion(hole, SkClipOp::kDifference);
1294 } while (layer->fNext);
1295 }
1296#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297}
1298
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001299int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001300 if (0xFF == alpha) {
1301 return this->saveLayer(bounds, nullptr);
1302 } else {
1303 SkPaint tmpPaint;
1304 tmpPaint.setAlpha(alpha);
1305 return this->saveLayer(bounds, &tmpPaint);
1306 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001307}
1308
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309void SkCanvas::internalRestore() {
1310 SkASSERT(fMCStack.count() != 0);
1311
1312 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313
reed687fa1c2015-04-07 08:00:56 -07001314 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001315
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001316 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317 DeviceCM* layer = fMCRec->fLayer; // may be null
1318 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001319 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320
1321 // now do the normal restore()
1322 fMCRec->~MCRec(); // balanced in save()
1323 fMCStack.pop_back();
1324 fMCRec = (MCRec*)fMCStack.back();
1325
Mike Reedc42a1cd2017-02-14 14:25:14 -05001326#ifdef SK_USE_DEVICE_CLIPPING
1327 if (fMCRec) {
1328 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1329 }
1330#endif
1331
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1333 since if we're being recorded, we don't want to record this (the
1334 recorder will have already recorded the restore).
1335 */
bsalomon49f085d2014-09-05 13:34:00 -07001336 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001337 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001338 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001339 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001340 // restore what we smashed in internalSaveLayer
1341 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001342 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001344 delete layer;
reedb679ca82015-04-07 04:40:48 -07001345 } else {
1346 // we're at the root
reeda499f902015-05-01 09:34:31 -07001347 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001348 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001349 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001351 }
msarettfbfa2582016-08-12 08:29:08 -07001352
1353 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001354 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001355 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1356 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001357}
1358
reede8f30622016-03-23 18:59:25 -07001359sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001360 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001361 props = &fProps;
1362 }
1363 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001364}
1365
reede8f30622016-03-23 18:59:25 -07001366sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001367 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001368 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001369}
1370
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001371SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001372 return this->onImageInfo();
1373}
1374
1375SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001376 SkBaseDevice* dev = this->getDevice();
1377 if (dev) {
1378 return dev->imageInfo();
1379 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001380 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001381 }
1382}
1383
brianosman898235c2016-04-06 07:38:23 -07001384bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001385 return this->onGetProps(props);
1386}
1387
1388bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001389 SkBaseDevice* dev = this->getDevice();
1390 if (dev) {
1391 if (props) {
1392 *props = fProps;
1393 }
1394 return true;
1395 } else {
1396 return false;
1397 }
1398}
1399
reed6ceeebd2016-03-09 14:26:26 -08001400bool SkCanvas::peekPixels(SkPixmap* pmap) {
1401 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001402}
1403
reed884e97c2015-05-26 11:31:54 -07001404bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001405 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001406 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001407}
1408
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001409void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001410 SkPixmap pmap;
1411 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001412 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001413 }
1414 if (info) {
1415 *info = pmap.info();
1416 }
1417 if (rowBytes) {
1418 *rowBytes = pmap.rowBytes();
1419 }
1420 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001421 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001422 }
reed884e97c2015-05-26 11:31:54 -07001423 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001424}
1425
reed884e97c2015-05-26 11:31:54 -07001426bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001427 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001428 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001429}
1430
reed@android.com8a1c16f2008-12-17 15:59:43 +00001431/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001432
reed7503d602016-07-15 14:23:29 -07001433void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001434 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001435 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436 paint = &tmp;
1437 }
reed@google.com4b226022011-01-11 18:32:13 +00001438
reed@google.com8926b162012-03-23 15:36:36 +00001439 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001440
reed@android.com8a1c16f2008-12-17 15:59:43 +00001441 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001442 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001443 paint = &looper.paint();
1444 SkImageFilter* filter = paint->getImageFilter();
1445 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001446 if (filter) {
1447 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1448 if (specialImage) {
1449 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1450 }
reed@google.com76dd2772012-01-05 21:15:07 +00001451 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001452 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001453 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001454 }
reeda2217ef2016-07-20 06:04:34 -07001455
reed@google.com4e2b3d32011-04-07 14:18:59 +00001456 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001457}
1458
reed32704672015-12-16 08:27:10 -08001459/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001460
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001461void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001462 if (dx || dy) {
1463 this->checkForDeferredSave();
1464 fDeviceCMDirty = true;
1465 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001466
reedfe69b502016-09-12 06:31:48 -07001467 // Translate shouldn't affect the is-scale-translateness of the matrix.
1468 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001469
Mike Reedc42a1cd2017-02-14 14:25:14 -05001470#ifdef SK_USE_DEVICE_CLIPPING
1471 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1472#endif
1473
reedfe69b502016-09-12 06:31:48 -07001474 this->didTranslate(dx,dy);
1475 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476}
1477
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001478void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001479 SkMatrix m;
1480 m.setScale(sx, sy);
1481 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482}
1483
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001484void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001485 SkMatrix m;
1486 m.setRotate(degrees);
1487 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488}
1489
bungeman7438bfc2016-07-12 15:01:19 -07001490void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1491 SkMatrix m;
1492 m.setRotate(degrees, px, py);
1493 this->concat(m);
1494}
1495
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001496void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001497 SkMatrix m;
1498 m.setSkew(sx, sy);
1499 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001500}
1501
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001502void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001503 if (matrix.isIdentity()) {
1504 return;
1505 }
1506
reed2ff1fce2014-12-11 07:07:37 -08001507 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001509 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001510 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001511
1512#ifdef SK_USE_DEVICE_CLIPPING
1513 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1514#endif
1515
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001516 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001517}
1518
reed8c30a812016-04-20 16:36:51 -07001519void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001520 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001521 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001522 fIsScaleTranslate = matrix.isScaleTranslate();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001523
1524#ifdef SK_USE_DEVICE_CLIPPING
1525 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1526#endif
reed8c30a812016-04-20 16:36:51 -07001527}
1528
1529void SkCanvas::setMatrix(const SkMatrix& matrix) {
1530 this->checkForDeferredSave();
1531 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001532 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001533}
1534
reed@android.com8a1c16f2008-12-17 15:59:43 +00001535void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001536 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001537}
1538
vjiaoblack95302da2016-07-21 10:25:54 -07001539#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001540void SkCanvas::translateZ(SkScalar z) {
1541 this->checkForDeferredSave();
1542 this->fMCRec->fCurDrawDepth += z;
1543 this->didTranslateZ(z);
1544}
1545
1546SkScalar SkCanvas::getZ() const {
1547 return this->fMCRec->fCurDrawDepth;
1548}
1549
vjiaoblack95302da2016-07-21 10:25:54 -07001550void SkCanvas::setLights(sk_sp<SkLights> lights) {
1551 this->fLights = lights;
1552}
1553
1554sk_sp<SkLights> SkCanvas::getLights() const {
1555 return this->fLights;
1556}
1557#endif
1558
reed@android.com8a1c16f2008-12-17 15:59:43 +00001559//////////////////////////////////////////////////////////////////////////////
1560
Mike Reedc1f77742016-12-09 09:00:50 -05001561void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001562 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001563 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1564 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001565}
1566
Mike Reedc1f77742016-12-09 09:00:50 -05001567void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001568 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001569
1570#ifdef SK_USE_DEVICE_CLIPPING
1571 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
1572#endif
1573
reedc64eff52015-11-21 12:39:45 -08001574 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001575 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1576 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1577 isAA);
reedc64eff52015-11-21 12:39:45 -08001578 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001579 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001580}
1581
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001582void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1583 fClipRestrictionRect = rect;
1584 fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
Mike Reedd519d482017-02-16 11:04:52 -05001585 if (fClipRestrictionRect.isEmpty()) {
1586 // we notify the device, but we *dont* resolve deferred saves (since we're just
1587 // removing the restriction if the rect is empty. how I hate this api.
1588#ifdef SK_USE_DEVICE_CLIPPING
1589 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
1590#endif
1591 } else {
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001592 this->checkForDeferredSave();
Mike Reedc42a1cd2017-02-14 14:25:14 -05001593#ifdef SK_USE_DEVICE_CLIPPING
Mike Reedd519d482017-02-16 11:04:52 -05001594 FOR_EACH_TOP_DEVICE(device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect));
Mike Reedc42a1cd2017-02-14 14:25:14 -05001595#endif
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001596 AutoValidateClip avc(this);
1597 fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
1598 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
1599 fDeviceCMDirty = true;
1600 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1601 }
1602}
1603
Mike Reedc1f77742016-12-09 09:00:50 -05001604void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001605 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001606 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001607 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001608 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1609 } else {
1610 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001611 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001612}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001613
Mike Reedc1f77742016-12-09 09:00:50 -05001614void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001615 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001616
Brian Salomona3b45d42016-10-03 11:36:16 -04001617 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001618
Brian Salomona3b45d42016-10-03 11:36:16 -04001619 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001620
1621#ifdef SK_USE_DEVICE_CLIPPING
1622 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
1623#endif
1624
Brian Salomona3b45d42016-10-03 11:36:16 -04001625 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1626 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1627 isAA);
1628 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1629 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001630}
1631
Mike Reedc1f77742016-12-09 09:00:50 -05001632void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001633 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001634 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001635
1636 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1637 SkRect r;
1638 if (path.isRect(&r)) {
1639 this->onClipRect(r, op, edgeStyle);
1640 return;
1641 }
1642 SkRRect rrect;
1643 if (path.isOval(&r)) {
1644 rrect.setOval(r);
1645 this->onClipRRect(rrect, op, edgeStyle);
1646 return;
1647 }
1648 if (path.isRRect(&rrect)) {
1649 this->onClipRRect(rrect, op, edgeStyle);
1650 return;
1651 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001652 }
robertphillips39f05382015-11-24 09:30:12 -08001653
1654 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001655}
1656
Mike Reedc1f77742016-12-09 09:00:50 -05001657void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001658 AutoValidateClip avc(this);
1659
reed@android.com8a1c16f2008-12-17 15:59:43 +00001660 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001661 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001662
1663#ifdef SK_USE_DEVICE_CLIPPING
1664 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
1665#endif
1666
Brian Salomona3b45d42016-10-03 11:36:16 -04001667 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001668
Brian Salomona3b45d42016-10-03 11:36:16 -04001669 const SkPath* rasterClipPath = &path;
1670 const SkMatrix* matrix = &fMCRec->fMatrix;
1671 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001672 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001673 isAA = getClipStack()->asPath(&tempPath);
1674 rasterClipPath = &tempPath;
1675 matrix = &SkMatrix::I();
Mike Reedc1f77742016-12-09 09:00:50 -05001676 op = kReplace_SkClipOp;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001677 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001678 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1679 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001680 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681}
1682
Mike Reedc1f77742016-12-09 09:00:50 -05001683void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001684 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001685 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001686}
1687
Mike Reedc1f77742016-12-09 09:00:50 -05001688void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001689#ifdef SK_USE_DEVICE_CLIPPING
1690 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
1691#endif
1692
reed@google.com5c3d1472011-02-22 19:12:23 +00001693 AutoValidateClip avc(this);
1694
reed@android.com8a1c16f2008-12-17 15:59:43 +00001695 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001696
reed@google.com5c3d1472011-02-22 19:12:23 +00001697 // todo: signal fClipStack that we have a region, and therefore (I guess)
1698 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001699 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001700
reed73603f32016-09-20 08:42:38 -07001701 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001702 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001703}
1704
reed@google.com819c9212011-02-23 18:56:55 +00001705#ifdef SK_DEBUG
1706void SkCanvas::validateClip() const {
1707 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001708 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001709 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001710 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001711 return;
1712 }
1713
reed@google.com819c9212011-02-23 18:56:55 +00001714 SkIRect ir;
1715 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001716 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001717
reed687fa1c2015-04-07 08:00:56 -07001718 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001719 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001720 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001721 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001722 case SkClipStack::Element::kRect_Type:
1723 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001724 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001725 break;
1726 case SkClipStack::Element::kEmpty_Type:
1727 tmpClip.setEmpty();
1728 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001729 default: {
1730 SkPath path;
1731 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001732 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1733 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001734 break;
1735 }
reed@google.com819c9212011-02-23 18:56:55 +00001736 }
1737 }
reed@google.com819c9212011-02-23 18:56:55 +00001738}
1739#endif
1740
reed@google.com90c07ea2012-04-13 13:50:27 +00001741void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001742 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001743 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001744
halcanary96fcdcc2015-08-27 07:41:13 -07001745 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001746 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001747 }
1748}
1749
reed@google.com5c3d1472011-02-22 19:12:23 +00001750///////////////////////////////////////////////////////////////////////////////
1751
reed@google.com754de5f2014-02-24 19:38:20 +00001752bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001753 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001754}
1755
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001756bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001757 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001758}
1759
msarettfbfa2582016-08-12 08:29:08 -07001760static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1761#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1762 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1763 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1764 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1765 return 0xF != _mm_movemask_ps(mask);
1766#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1767 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1768 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1769 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1770 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1771#else
1772 SkRect devRectAsRect;
1773 SkRect devClipAsRect;
1774 devRect.store(&devRectAsRect.fLeft);
1775 devClip.store(&devClipAsRect.fLeft);
1776 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1777#endif
1778}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001779
msarettfbfa2582016-08-12 08:29:08 -07001780// It's important for this function to not be inlined. Otherwise the compiler will share code
1781// between the fast path and the slow path, resulting in two slow paths.
1782static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1783 const SkMatrix& matrix) {
1784 SkRect deviceRect;
1785 matrix.mapRect(&deviceRect, src);
1786 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1787}
1788
1789bool SkCanvas::quickReject(const SkRect& src) const {
1790#ifdef SK_DEBUG
1791 // Verify that fDeviceClipBounds are set properly.
1792 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001793 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001794 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001795 } else {
msarettfbfa2582016-08-12 08:29:08 -07001796 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001797 }
msarettfbfa2582016-08-12 08:29:08 -07001798
msarett9637ea92016-08-18 14:03:30 -07001799 // Verify that fIsScaleTranslate is set properly.
1800 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001801#endif
1802
msarett9637ea92016-08-18 14:03:30 -07001803 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001804 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1805 }
1806
1807 // We inline the implementation of mapScaleTranslate() for the fast path.
1808 float sx = fMCRec->fMatrix.getScaleX();
1809 float sy = fMCRec->fMatrix.getScaleY();
1810 float tx = fMCRec->fMatrix.getTranslateX();
1811 float ty = fMCRec->fMatrix.getTranslateY();
1812 Sk4f scale(sx, sy, sx, sy);
1813 Sk4f trans(tx, ty, tx, ty);
1814
1815 // Apply matrix.
1816 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1817
1818 // Make sure left < right, top < bottom.
1819 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1820 Sk4f min = Sk4f::Min(ltrb, rblt);
1821 Sk4f max = Sk4f::Max(ltrb, rblt);
1822 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1823 // ARM this sequence generates the fastest (a single instruction).
1824 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1825
1826 // Check if the device rect is NaN or outside the clip.
1827 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001828}
1829
reed@google.com3b3e8952012-08-16 20:53:31 +00001830bool SkCanvas::quickReject(const SkPath& path) const {
1831 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001832}
1833
Mike Reed42e8c532017-01-23 14:09:13 -05001834SkRect SkCanvas::onGetLocalClipBounds() const {
1835 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001836 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001837 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001838 }
1839
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001840 SkMatrix inverse;
1841 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001842 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001843 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001844 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001845
Mike Reed42e8c532017-01-23 14:09:13 -05001846 SkRect bounds;
1847 SkRect r;
1848 // adjust it outwards in case we are antialiasing
1849 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001850
Mike Reed42e8c532017-01-23 14:09:13 -05001851 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1852 ibounds.fRight + inset, ibounds.fBottom + inset);
1853 inverse.mapRect(&bounds, r);
1854 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001855}
1856
Mike Reed42e8c532017-01-23 14:09:13 -05001857SkIRect SkCanvas::onGetDeviceClipBounds() const {
reed1f836ee2014-07-07 07:49:34 -07001858 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001859 if (clip.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001860 return SkIRect::MakeEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001861 }
Mike Reed42e8c532017-01-23 14:09:13 -05001862 return clip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001863}
1864
reed@android.com8a1c16f2008-12-17 15:59:43 +00001865const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001866 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001867}
1868
Mike Reed3726a4a2017-01-19 11:36:41 -05001869void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1870 // we know that ganesh doesn't track the rgn, so ask for its clipstack
1871 if (this->getGrContext()) {
Stan Iliev4eabd5d2017-02-21 11:15:53 -05001872 const SkClipStack* cs = this->getClipStack();
1873 SkClipStack::BoundsType boundType;
1874 bool isIntersectionOfRects;
1875 SkRect bounds;
1876 cs->getBounds(&bounds, &boundType, &isIntersectionOfRects);
1877 if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
1878 rgn->setRect(bounds.round());
1879 return;
1880 }
Mike Reed3726a4a2017-01-19 11:36:41 -05001881 SkPath path;
Stan Iliev4eabd5d2017-02-21 11:15:53 -05001882 cs->asPath(&path);
Mike Reed3726a4a2017-01-19 11:36:41 -05001883 SkISize size = this->getBaseLayerSize();
1884 rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
1885 } else {
1886 *rgn = fMCRec->fRasterClip.forceGetBW();
1887 }
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001888}
1889
Brian Osman11052242016-10-27 14:47:55 -04001890GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001891 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001892 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001893}
1894
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001895GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001896 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001897 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001898}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001899
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001900void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1901 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001902 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001903 if (outer.isEmpty()) {
1904 return;
1905 }
1906 if (inner.isEmpty()) {
1907 this->drawRRect(outer, paint);
1908 return;
1909 }
1910
1911 // We don't have this method (yet), but technically this is what we should
1912 // be able to assert...
1913 // SkASSERT(outer.contains(inner));
1914 //
1915 // For now at least check for containment of bounds
1916 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1917
1918 this->onDrawDRRect(outer, inner, paint);
1919}
1920
reed41af9662015-01-05 07:49:08 -08001921// These need to stop being virtual -- clients need to override the onDraw... versions
1922
1923void SkCanvas::drawPaint(const SkPaint& paint) {
1924 this->onDrawPaint(paint);
1925}
1926
1927void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1928 this->onDrawRect(r, paint);
1929}
1930
msarettdca352e2016-08-26 06:37:45 -07001931void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1932 if (region.isEmpty()) {
1933 return;
1934 }
1935
1936 if (region.isRect()) {
1937 return this->drawIRect(region.getBounds(), paint);
1938 }
1939
1940 this->onDrawRegion(region, paint);
1941}
1942
reed41af9662015-01-05 07:49:08 -08001943void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1944 this->onDrawOval(r, paint);
1945}
1946
1947void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1948 this->onDrawRRect(rrect, paint);
1949}
1950
1951void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1952 this->onDrawPoints(mode, count, pts, paint);
1953}
1954
1955void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001956 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001957 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001958 this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices,
1959 indexCount, paint);
1960}
1961
1962void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint,
1963 uint32_t flags) {
1964 RETURN_ON_NULL(vertices);
1965 this->onDrawVerticesObject(std::move(vertices), mode, paint, flags);
reed41af9662015-01-05 07:49:08 -08001966}
1967
1968void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1969 this->onDrawPath(path, paint);
1970}
1971
reeda85d4d02015-05-06 12:56:48 -07001972void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001973 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001974 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001975}
1976
reede47829b2015-08-06 10:02:53 -07001977void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1978 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001979 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001980 if (dst.isEmpty() || src.isEmpty()) {
1981 return;
1982 }
1983 this->onDrawImageRect(image, &src, dst, paint, constraint);
1984}
reed41af9662015-01-05 07:49:08 -08001985
reed84984ef2015-07-17 07:09:43 -07001986void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1987 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001988 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001989 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001990}
1991
reede47829b2015-08-06 10:02:53 -07001992void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1993 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001994 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001995 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1996 constraint);
1997}
reede47829b2015-08-06 10:02:53 -07001998
reed4c21dc52015-06-25 12:32:03 -07001999void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2000 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002001 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07002002 if (dst.isEmpty()) {
2003 return;
2004 }
msarett552bca92016-08-03 06:53:26 -07002005 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
2006 this->onDrawImageNine(image, center, dst, paint);
2007 } else {
reede47829b2015-08-06 10:02:53 -07002008 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002009 }
reed4c21dc52015-06-25 12:32:03 -07002010}
2011
msarett16882062016-08-16 09:31:08 -07002012void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2013 const SkPaint* paint) {
2014 RETURN_ON_NULL(image);
2015 if (dst.isEmpty()) {
2016 return;
2017 }
msarett71df2d72016-09-30 12:41:42 -07002018
2019 SkIRect bounds;
2020 Lattice latticePlusBounds = lattice;
2021 if (!latticePlusBounds.fBounds) {
2022 bounds = SkIRect::MakeWH(image->width(), image->height());
2023 latticePlusBounds.fBounds = &bounds;
2024 }
2025
2026 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
2027 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07002028 } else {
2029 this->drawImageRect(image, dst, paint);
2030 }
2031}
2032
reed41af9662015-01-05 07:49:08 -08002033void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002034 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002035 return;
2036 }
reed41af9662015-01-05 07:49:08 -08002037 this->onDrawBitmap(bitmap, dx, dy, paint);
2038}
2039
reede47829b2015-08-06 10:02:53 -07002040void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002041 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002042 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002043 return;
2044 }
reede47829b2015-08-06 10:02:53 -07002045 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002046}
2047
reed84984ef2015-07-17 07:09:43 -07002048void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2049 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002050 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002051}
2052
reede47829b2015-08-06 10:02:53 -07002053void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2054 SrcRectConstraint constraint) {
2055 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2056 constraint);
2057}
reede47829b2015-08-06 10:02:53 -07002058
reed41af9662015-01-05 07:49:08 -08002059void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2060 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002061 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002062 return;
2063 }
msarett552bca92016-08-03 06:53:26 -07002064 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2065 this->onDrawBitmapNine(bitmap, center, dst, paint);
2066 } else {
reeda5517e22015-07-14 10:54:12 -07002067 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002068 }
reed41af9662015-01-05 07:49:08 -08002069}
2070
msarettc573a402016-08-02 08:05:56 -07002071void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2072 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002073 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002074 return;
2075 }
msarett71df2d72016-09-30 12:41:42 -07002076
2077 SkIRect bounds;
2078 Lattice latticePlusBounds = lattice;
2079 if (!latticePlusBounds.fBounds) {
2080 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2081 latticePlusBounds.fBounds = &bounds;
2082 }
2083
2084 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2085 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002086 } else {
msarett16882062016-08-16 09:31:08 -07002087 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002088 }
msarettc573a402016-08-02 08:05:56 -07002089}
2090
reed71c3c762015-06-24 10:29:17 -07002091void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002092 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002093 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002094 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002095 if (count <= 0) {
2096 return;
2097 }
Joe Gregorioc4859072017-01-20 14:21:27 +00002098 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002099 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002100 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002101}
2102
reedf70b5312016-03-04 16:36:20 -08002103void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2104 if (key) {
2105 this->onDrawAnnotation(rect, key, value);
2106 }
2107}
2108
reede47829b2015-08-06 10:02:53 -07002109void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2110 const SkPaint* paint, SrcRectConstraint constraint) {
2111 if (src) {
2112 this->drawImageRect(image, *src, dst, paint, constraint);
2113 } else {
2114 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2115 dst, paint, constraint);
2116 }
2117}
2118void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2119 const SkPaint* paint, SrcRectConstraint constraint) {
2120 if (src) {
2121 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2122 } else {
2123 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2124 dst, paint, constraint);
2125 }
2126}
2127
tomhudsoncb3bd182016-05-18 07:24:16 -07002128void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2129 SkIRect layer_bounds = this->getTopLayerBounds();
2130 if (matrix) {
2131 *matrix = this->getTotalMatrix();
2132 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2133 }
2134 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05002135 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07002136 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2137 }
2138}
2139
reed@android.com8a1c16f2008-12-17 15:59:43 +00002140//////////////////////////////////////////////////////////////////////////////
2141// These are the virtual drawing methods
2142//////////////////////////////////////////////////////////////////////////////
2143
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002144void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002145 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002146 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2147 }
2148}
2149
reed41af9662015-01-05 07:49:08 -08002150void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002151 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002152 this->internalDrawPaint(paint);
2153}
2154
2155void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002156 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002157
2158 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002159 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002160 }
2161
reed@google.com4e2b3d32011-04-07 14:18:59 +00002162 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002163}
2164
reed41af9662015-01-05 07:49:08 -08002165void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2166 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002167 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002168 if ((long)count <= 0) {
2169 return;
2170 }
2171
Mike Reed822128b2017-02-28 16:41:03 -05002172 SkRect r;
halcanary96fcdcc2015-08-27 07:41:13 -07002173 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002174 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002175 // special-case 2 points (common for drawing a single line)
2176 if (2 == count) {
2177 r.set(pts[0], pts[1]);
2178 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002179 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002180 }
Mike Reed822128b2017-02-28 16:41:03 -05002181 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002182 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2183 return;
2184 }
2185 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002186 }
reed@google.coma584aed2012-05-16 14:06:02 +00002187
halcanary96fcdcc2015-08-27 07:41:13 -07002188 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002189
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002190 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002191
reed@android.com8a1c16f2008-12-17 15:59:43 +00002192 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002193 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002194 }
reed@google.com4b226022011-01-11 18:32:13 +00002195
reed@google.com4e2b3d32011-04-07 14:18:59 +00002196 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002197}
2198
reed4a167172016-08-18 17:15:25 -07002199static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2200 return ((intptr_t)paint.getImageFilter() |
2201#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2202 (intptr_t)canvas->getDrawFilter() |
2203#endif
2204 (intptr_t)paint.getLooper() ) != 0;
2205}
2206
reed41af9662015-01-05 07:49:08 -08002207void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002208 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002209 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002210 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2211 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2212 SkRect tmp(r);
2213 tmp.sort();
2214
Mike Reed822128b2017-02-28 16:41:03 -05002215 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002216 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2217 return;
2218 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002219 }
reed@google.com4b226022011-01-11 18:32:13 +00002220
reed4a167172016-08-18 17:15:25 -07002221 if (needs_autodrawlooper(this, paint)) {
Mike Reed822128b2017-02-28 16:41:03 -05002222 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, &r, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002223
reed4a167172016-08-18 17:15:25 -07002224 while (iter.next()) {
2225 iter.fDevice->drawRect(iter, r, looper.paint());
2226 }
2227
2228 LOOPER_END
2229 } else {
Mike Reed822128b2017-02-28 16:41:03 -05002230 this->predrawNotify(&r, &paint, false);
reed4a167172016-08-18 17:15:25 -07002231 SkDrawIter iter(this);
2232 while (iter.next()) {
2233 iter.fDevice->drawRect(iter, r, paint);
2234 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002235 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002236}
2237
msarett44df6512016-08-25 13:54:30 -07002238void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
msarett44df6512016-08-25 13:54:30 -07002239 SkRect regionRect = SkRect::Make(region.getBounds());
msarett44df6512016-08-25 13:54:30 -07002240 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002241 SkRect storage;
msarett44df6512016-08-25 13:54:30 -07002242 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2243 return;
2244 }
msarett44df6512016-08-25 13:54:30 -07002245 }
2246
Mike Reed822128b2017-02-28 16:41:03 -05002247 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, &regionRect)
msarett44df6512016-08-25 13:54:30 -07002248
2249 while (iter.next()) {
2250 iter.fDevice->drawRegion(iter, region, looper.paint());
2251 }
2252
2253 LOOPER_END
2254}
2255
reed41af9662015-01-05 07:49:08 -08002256void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002257 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002258 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002259 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002260 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2261 return;
2262 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002263 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002264
Mike Reed822128b2017-02-28 16:41:03 -05002265 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002266
2267 while (iter.next()) {
2268 iter.fDevice->drawOval(iter, oval, looper.paint());
2269 }
2270
2271 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002272}
2273
bsalomonac3aa242016-08-19 11:25:19 -07002274void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2275 SkScalar sweepAngle, bool useCenter,
2276 const SkPaint& paint) {
2277 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomonac3aa242016-08-19 11:25:19 -07002278 if (paint.canComputeFastBounds()) {
2279 SkRect storage;
2280 // Note we're using the entire oval as the bounds.
2281 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2282 return;
2283 }
bsalomonac3aa242016-08-19 11:25:19 -07002284 }
2285
Mike Reed822128b2017-02-28 16:41:03 -05002286 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, &oval)
bsalomonac3aa242016-08-19 11:25:19 -07002287
2288 while (iter.next()) {
2289 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2290 }
2291
2292 LOOPER_END
2293}
2294
reed41af9662015-01-05 07:49:08 -08002295void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002296 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
reed@google.com4ed0fb72012-12-12 20:48:18 +00002297 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002298 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002299 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2300 return;
2301 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002302 }
2303
2304 if (rrect.isRect()) {
2305 // call the non-virtual version
2306 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002307 return;
2308 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002309 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002310 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2311 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002312 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002313
Mike Reed822128b2017-02-28 16:41:03 -05002314 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &rrect.getBounds())
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002315
2316 while (iter.next()) {
2317 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2318 }
2319
2320 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002321}
2322
Mike Reed822128b2017-02-28 16:41:03 -05002323void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002324 if (paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002325 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002326 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2327 return;
2328 }
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002329 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002330
Mike Reed822128b2017-02-28 16:41:03 -05002331 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, &outer.getBounds())
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002332
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002333 while (iter.next()) {
2334 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2335 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002336
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002337 LOOPER_END
2338}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002339
reed41af9662015-01-05 07:49:08 -08002340void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002341 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002342 if (!path.isFinite()) {
2343 return;
2344 }
2345
Mike Reed822128b2017-02-28 16:41:03 -05002346 const SkRect& pathBounds = path.getBounds();
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002347 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
Mike Reed822128b2017-02-28 16:41:03 -05002348 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002349 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2350 return;
2351 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002352 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002353
Mike Reed822128b2017-02-28 16:41:03 -05002354 if (pathBounds.width() <= 0 && pathBounds.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002355 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002356 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002357 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002358 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002359 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002360
Mike Reed822128b2017-02-28 16:41:03 -05002361 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002362
2363 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002364 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002365 }
2366
reed@google.com4e2b3d32011-04-07 14:18:59 +00002367 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002368}
2369
reed262a71b2015-12-05 13:07:27 -08002370bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002371 if (!paint.getImageFilter()) {
2372 return false;
2373 }
2374
2375 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002376 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002377 return false;
2378 }
2379
2380 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2381 // Once we can filter and the filter will return a result larger than itself, we should be
2382 // able to remove this constraint.
2383 // skbug.com/4526
2384 //
2385 SkPoint pt;
2386 ctm.mapXY(x, y, &pt);
2387 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2388 return ir.contains(fMCRec->fRasterClip.getBounds());
2389}
2390
reeda85d4d02015-05-06 12:56:48 -07002391void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002392 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002393 SkRect bounds = SkRect::MakeXYWH(x, y,
2394 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002395 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002396 SkRect tmp = bounds;
2397 if (paint) {
2398 paint->computeFastBounds(tmp, &tmp);
2399 }
2400 if (this->quickReject(tmp)) {
2401 return;
2402 }
reeda85d4d02015-05-06 12:56:48 -07002403 }
halcanary9d524f22016-03-29 09:03:52 -07002404
reeda85d4d02015-05-06 12:56:48 -07002405 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002406 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002407 paint = lazy.init();
2408 }
reed262a71b2015-12-05 13:07:27 -08002409
reeda2217ef2016-07-20 06:04:34 -07002410 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002411 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2412 *paint);
2413 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002414 special = this->getDevice()->makeSpecial(image);
2415 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002416 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002417 }
2418 }
2419
reed262a71b2015-12-05 13:07:27 -08002420 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2421
reeda85d4d02015-05-06 12:56:48 -07002422 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002423 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002424 if (special) {
2425 SkPoint pt;
2426 iter.fMatrix->mapXY(x, y, &pt);
2427 iter.fDevice->drawSpecial(iter, special.get(),
2428 SkScalarRoundToInt(pt.fX),
2429 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002430 } else {
2431 iter.fDevice->drawImage(iter, image, x, y, pnt);
2432 }
reeda85d4d02015-05-06 12:56:48 -07002433 }
halcanary9d524f22016-03-29 09:03:52 -07002434
reeda85d4d02015-05-06 12:56:48 -07002435 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002436}
2437
reed41af9662015-01-05 07:49:08 -08002438void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002439 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002440 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002441 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002442 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002443 if (paint) {
2444 paint->computeFastBounds(dst, &storage);
2445 }
2446 if (this->quickReject(storage)) {
2447 return;
2448 }
reeda85d4d02015-05-06 12:56:48 -07002449 }
2450 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002451 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002452 paint = lazy.init();
2453 }
halcanary9d524f22016-03-29 09:03:52 -07002454
senorblancoc41e7e12015-12-07 12:51:30 -08002455 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002456 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002457
reeda85d4d02015-05-06 12:56:48 -07002458 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002459 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002460 }
halcanary9d524f22016-03-29 09:03:52 -07002461
reeda85d4d02015-05-06 12:56:48 -07002462 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002463}
2464
reed41af9662015-01-05 07:49:08 -08002465void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002466 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002467 SkDEBUGCODE(bitmap.validate();)
2468
reed33366972015-10-08 09:22:02 -07002469 if (bitmap.drawsNothing()) {
2470 return;
2471 }
2472
2473 SkLazyPaint lazy;
2474 if (nullptr == paint) {
2475 paint = lazy.init();
2476 }
2477
Mike Reed822128b2017-02-28 16:41:03 -05002478 SkRect bounds;
2479 bitmap.getBounds(&bounds);
2480 bounds.offset(x, y);
2481 bool canFastBounds = paint->canComputeFastBounds();
2482 if (canFastBounds) {
2483 SkRect storage;
2484 if (this->quickReject(paint->computeFastBounds(bounds, &storage))) {
senorblanco87e066e2015-10-28 11:23:36 -07002485 return;
2486 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002487 }
reed@google.com4b226022011-01-11 18:32:13 +00002488
reeda2217ef2016-07-20 06:04:34 -07002489 sk_sp<SkSpecialImage> special;
Mike Reed822128b2017-02-28 16:41:03 -05002490 bool drawAsSprite = canFastBounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2491 bitmap.height(), *paint);
reed129ed1c2016-02-22 06:42:31 -08002492 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002493 special = this->getDevice()->makeSpecial(bitmap);
2494 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002495 drawAsSprite = false;
2496 }
2497 }
2498
Mike Reed822128b2017-02-28 16:41:03 -05002499 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2500
2501 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
reed33366972015-10-08 09:22:02 -07002502
2503 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002504 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002505 if (special) {
reed262a71b2015-12-05 13:07:27 -08002506 SkPoint pt;
2507 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002508 iter.fDevice->drawSpecial(iter, special.get(),
2509 SkScalarRoundToInt(pt.fX),
2510 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002511 } else {
2512 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2513 }
reed33366972015-10-08 09:22:02 -07002514 }
msarettfbfa2582016-08-12 08:29:08 -07002515
reed33366972015-10-08 09:22:02 -07002516 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002517}
2518
reed@google.com9987ec32011-09-07 11:57:52 +00002519// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002520void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002521 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002522 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002523 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002524 return;
2525 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002526
halcanary96fcdcc2015-08-27 07:41:13 -07002527 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002528 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002529 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2530 return;
2531 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002532 }
reed@google.com3d608122011-11-21 15:16:16 +00002533
reed@google.com33535f32012-09-25 15:37:50 +00002534 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002535 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002536 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002537 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002538
senorblancoc41e7e12015-12-07 12:51:30 -08002539 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002540 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002541
reed@google.com33535f32012-09-25 15:37:50 +00002542 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002543 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002544 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002545
reed@google.com33535f32012-09-25 15:37:50 +00002546 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002547}
2548
reed41af9662015-01-05 07:49:08 -08002549void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002550 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002551 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002552 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002553 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002554}
2555
reed4c21dc52015-06-25 12:32:03 -07002556void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2557 const SkPaint* paint) {
2558 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002559
halcanary96fcdcc2015-08-27 07:41:13 -07002560 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002561 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002562 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2563 return;
2564 }
reed@google.com3d608122011-11-21 15:16:16 +00002565 }
halcanary9d524f22016-03-29 09:03:52 -07002566
reed4c21dc52015-06-25 12:32:03 -07002567 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002568 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002569 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002570 }
halcanary9d524f22016-03-29 09:03:52 -07002571
senorblancoc41e7e12015-12-07 12:51:30 -08002572 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002573
reed4c21dc52015-06-25 12:32:03 -07002574 while (iter.next()) {
2575 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002576 }
halcanary9d524f22016-03-29 09:03:52 -07002577
reed4c21dc52015-06-25 12:32:03 -07002578 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002579}
2580
reed41af9662015-01-05 07:49:08 -08002581void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2582 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002583 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002584 SkDEBUGCODE(bitmap.validate();)
2585
halcanary96fcdcc2015-08-27 07:41:13 -07002586 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002587 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002588 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2589 return;
2590 }
reed4c21dc52015-06-25 12:32:03 -07002591 }
halcanary9d524f22016-03-29 09:03:52 -07002592
reed4c21dc52015-06-25 12:32:03 -07002593 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002594 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002595 paint = lazy.init();
2596 }
halcanary9d524f22016-03-29 09:03:52 -07002597
senorblancoc41e7e12015-12-07 12:51:30 -08002598 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002599
reed4c21dc52015-06-25 12:32:03 -07002600 while (iter.next()) {
2601 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2602 }
halcanary9d524f22016-03-29 09:03:52 -07002603
reed4c21dc52015-06-25 12:32:03 -07002604 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002605}
2606
msarett16882062016-08-16 09:31:08 -07002607void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2608 const SkPaint* paint) {
2609 if (nullptr == paint || paint->canComputeFastBounds()) {
2610 SkRect storage;
2611 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2612 return;
2613 }
2614 }
2615
2616 SkLazyPaint lazy;
2617 if (nullptr == paint) {
2618 paint = lazy.init();
2619 }
2620
2621 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2622
2623 while (iter.next()) {
2624 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2625 }
2626
2627 LOOPER_END
2628}
2629
2630void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2631 const SkRect& dst, const SkPaint* paint) {
2632 if (nullptr == paint || paint->canComputeFastBounds()) {
2633 SkRect storage;
2634 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2635 return;
2636 }
2637 }
2638
2639 SkLazyPaint lazy;
2640 if (nullptr == paint) {
2641 paint = lazy.init();
2642 }
2643
2644 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2645
2646 while (iter.next()) {
2647 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2648 }
2649
2650 LOOPER_END
2651}
2652
reed@google.comf67e4cf2011-03-15 20:56:58 +00002653class SkDeviceFilteredPaint {
2654public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002655 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002656 uint32_t filteredFlags = device->filterTextFlags(paint);
2657 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002658 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002659 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002660 fPaint = newPaint;
2661 } else {
2662 fPaint = &paint;
2663 }
2664 }
2665
reed@google.comf67e4cf2011-03-15 20:56:58 +00002666 const SkPaint& paint() const { return *fPaint; }
2667
2668private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002669 const SkPaint* fPaint;
2670 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002671};
2672
reed@google.come0d9ce82014-04-23 04:00:17 +00002673void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2674 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002675 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002676
2677 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002678 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002679 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002680 }
2681
reed@google.com4e2b3d32011-04-07 14:18:59 +00002682 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002683}
2684
reed@google.come0d9ce82014-04-23 04:00:17 +00002685void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2686 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002687 SkPoint textOffset = SkPoint::Make(0, 0);
2688
halcanary96fcdcc2015-08-27 07:41:13 -07002689 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002690
reed@android.com8a1c16f2008-12-17 15:59:43 +00002691 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002692 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002693 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002694 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002695 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002696
reed@google.com4e2b3d32011-04-07 14:18:59 +00002697 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002698}
2699
reed@google.come0d9ce82014-04-23 04:00:17 +00002700void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2701 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002702
2703 SkPoint textOffset = SkPoint::Make(0, constY);
2704
halcanary96fcdcc2015-08-27 07:41:13 -07002705 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002706
reed@android.com8a1c16f2008-12-17 15:59:43 +00002707 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002708 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002709 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002710 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002712
reed@google.com4e2b3d32011-04-07 14:18:59 +00002713 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002714}
2715
reed@google.come0d9ce82014-04-23 04:00:17 +00002716void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2717 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002718 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002719
reed@android.com8a1c16f2008-12-17 15:59:43 +00002720 while (iter.next()) {
2721 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002722 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002724
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002725 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002726}
2727
reed45561a02016-07-07 12:47:17 -07002728void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2729 const SkRect* cullRect, const SkPaint& paint) {
2730 if (cullRect && this->quickReject(*cullRect)) {
2731 return;
2732 }
2733
2734 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2735
2736 while (iter.next()) {
2737 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2738 }
2739
2740 LOOPER_END
2741}
2742
fmalita00d5c2c2014-08-21 08:53:26 -07002743void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2744 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002745
fmalita85d5eb92015-03-04 11:20:12 -08002746 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002747 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002748 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002749 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002750 SkRect tmp;
2751 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2752 return;
2753 }
2754 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002755 }
2756
fmalita024f9962015-03-03 19:08:17 -08002757 // We cannot filter in the looper as we normally do, because the paint is
2758 // incomplete at this point (text-related attributes are embedded within blob run paints).
2759 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002760 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002761
fmalita85d5eb92015-03-04 11:20:12 -08002762 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002763
fmalitaaa1b9122014-08-28 14:32:24 -07002764 while (iter.next()) {
2765 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002766 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002767 }
2768
fmalitaaa1b9122014-08-28 14:32:24 -07002769 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002770
2771 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002772}
2773
reed@google.come0d9ce82014-04-23 04:00:17 +00002774// These will become non-virtual, so they always call the (virtual) onDraw... method
2775void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2776 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002777 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002778 if (byteLength) {
2779 this->onDrawText(text, byteLength, x, y, paint);
2780 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002781}
2782void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2783 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002784 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002785 if (byteLength) {
2786 this->onDrawPosText(text, byteLength, pos, paint);
2787 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002788}
2789void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2790 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002791 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002792 if (byteLength) {
2793 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2794 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002795}
2796void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2797 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002798 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002799 if (byteLength) {
2800 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2801 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002802}
reed45561a02016-07-07 12:47:17 -07002803void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2804 const SkRect* cullRect, const SkPaint& paint) {
2805 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2806 if (byteLength) {
2807 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2808 }
2809}
fmalita00d5c2c2014-08-21 08:53:26 -07002810void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2811 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002812 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002813 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002814 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002815}
reed@google.come0d9ce82014-04-23 04:00:17 +00002816
reed41af9662015-01-05 07:49:08 -08002817void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2818 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002819 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002820 const uint16_t indices[], int indexCount,
2821 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002822 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002823 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002824
reed@android.com8a1c16f2008-12-17 15:59:43 +00002825 while (iter.next()) {
2826 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002827 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002828 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002829 }
reed@google.com4b226022011-01-11 18:32:13 +00002830
reed@google.com4e2b3d32011-04-07 14:18:59 +00002831 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002832}
2833
Brian Salomon199fb872017-02-06 09:41:10 -05002834void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode,
2835 const SkPaint& paint, uint32_t flags) {
2836 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2837 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2838
2839 while (iter.next()) {
2840 // In the common case of one iteration we could std::move vertices here.
2841 iter.fDevice->drawVerticesObject(iter, vertices, bmode, looper.paint(), flags);
2842 }
2843
2844 LOOPER_END
2845}
2846
2847void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode,
2848 const SkPaint& paint, uint32_t flags) {
2849 const SkPoint* texs =
2850 (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords();
2851 const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors();
2852 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs,
2853 colors, mode, vertices->indices(), vertices->indexCount(), paint);
2854}
2855
dandovb3c9d1c2014-08-12 08:34:29 -07002856void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002857 const SkPoint texCoords[4], SkBlendMode bmode,
2858 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002859 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002860 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002861 return;
2862 }
mtklein6cfa73a2014-08-13 13:33:49 -07002863
Mike Reedfaba3712016-11-03 14:45:31 -04002864 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002865}
2866
2867void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002868 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002869 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002870 // Since a patch is always within the convex hull of the control points, we discard it when its
2871 // bounding rectangle is completely outside the current clip.
2872 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002873 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002874 if (this->quickReject(bounds)) {
2875 return;
2876 }
mtklein6cfa73a2014-08-13 13:33:49 -07002877
halcanary96fcdcc2015-08-27 07:41:13 -07002878 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002879
dandovecfff212014-08-04 10:02:00 -07002880 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002881 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002882 }
mtklein6cfa73a2014-08-13 13:33:49 -07002883
dandovecfff212014-08-04 10:02:00 -07002884 LOOPER_END
2885}
2886
reeda8db7282015-07-07 10:22:31 -07002887void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002888 RETURN_ON_NULL(dr);
2889 if (x || y) {
2890 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2891 this->onDrawDrawable(dr, &matrix);
2892 } else {
2893 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002894 }
2895}
2896
reeda8db7282015-07-07 10:22:31 -07002897void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002898 RETURN_ON_NULL(dr);
2899 if (matrix && matrix->isIdentity()) {
2900 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002901 }
reede3b38ce2016-01-08 09:18:44 -08002902 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002903}
2904
2905void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002906 // drawable bounds are no longer reliable (e.g. android displaylist)
2907 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002908 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002909}
2910
reed71c3c762015-06-24 10:29:17 -07002911void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002912 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002913 const SkRect* cull, const SkPaint* paint) {
2914 if (cull && this->quickReject(*cull)) {
2915 return;
2916 }
2917
2918 SkPaint pnt;
2919 if (paint) {
2920 pnt = *paint;
2921 }
halcanary9d524f22016-03-29 09:03:52 -07002922
halcanary96fcdcc2015-08-27 07:41:13 -07002923 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002924 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002925 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002926 }
2927 LOOPER_END
2928}
2929
reedf70b5312016-03-04 16:36:20 -08002930void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2931 SkASSERT(key);
2932
2933 SkPaint paint;
2934 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2935 while (iter.next()) {
2936 iter.fDevice->drawAnnotation(iter, rect, key, value);
2937 }
2938 LOOPER_END
2939}
2940
reed@android.com8a1c16f2008-12-17 15:59:43 +00002941//////////////////////////////////////////////////////////////////////////////
2942// These methods are NOT virtual, and therefore must call back into virtual
2943// methods, rather than actually drawing themselves.
2944//////////////////////////////////////////////////////////////////////////////
2945
Mike Reed3661bc92017-02-22 13:21:42 -05002946#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed374772b2016-10-05 17:33:02 -07002947void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002948 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002949 SkPaint paint;
2950
2951 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002952 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002953 this->drawPaint(paint);
2954}
Mike Reed3661bc92017-02-22 13:21:42 -05002955#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002956
reed374772b2016-10-05 17:33:02 -07002957void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002958 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002959 SkPaint paint;
2960
2961 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002962 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002963 this->drawPaint(paint);
2964}
2965
2966void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002967 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
Mike Reed3661bc92017-02-22 13:21:42 -05002968 const SkPoint pt = { x, y };
reed@android.com8a1c16f2008-12-17 15:59:43 +00002969 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2970}
2971
Mike Reed3661bc92017-02-22 13:21:42 -05002972#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002973void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002974 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002975 SkPoint pt;
2976 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002977
reed@android.com8a1c16f2008-12-17 15:59:43 +00002978 pt.set(x, y);
2979 paint.setColor(color);
2980 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2981}
Mike Reed3661bc92017-02-22 13:21:42 -05002982#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002983
Mike Reed3661bc92017-02-22 13:21:42 -05002984void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002985 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002986 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002987
reed@android.com8a1c16f2008-12-17 15:59:43 +00002988 pts[0].set(x0, y0);
2989 pts[1].set(x1, y1);
2990 this->drawPoints(kLines_PointMode, 2, pts, paint);
2991}
2992
Mike Reed3661bc92017-02-22 13:21:42 -05002993#ifdef SK_SUPPORT_LEGACY_CANVAS_HELPERS
reed@android.com8a1c16f2008-12-17 15:59:43 +00002994void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2995 SkScalar right, SkScalar bottom,
2996 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002997 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002998 SkRect r;
2999
3000 r.set(left, top, right, bottom);
3001 this->drawRect(r, paint);
3002}
Mike Reed3661bc92017-02-22 13:21:42 -05003003#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00003004
Mike Reed3661bc92017-02-22 13:21:42 -05003005void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003006 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003007 if (radius < 0) {
3008 radius = 0;
3009 }
3010
3011 SkRect r;
3012 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003013 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003014}
3015
3016void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3017 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003018 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003019 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003020 SkRRect rrect;
3021 rrect.setRectXY(r, rx, ry);
3022 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003023 } else {
3024 this->drawRect(r, paint);
3025 }
3026}
3027
reed@android.com8a1c16f2008-12-17 15:59:43 +00003028void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3029 SkScalar sweepAngle, bool useCenter,
3030 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003031 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003032 if (oval.isEmpty() || !sweepAngle) {
3033 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003034 }
bsalomon21af9ca2016-08-25 12:29:23 -07003035 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003036}
3037
3038void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3039 const SkPath& path, SkScalar hOffset,
3040 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003041 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003042 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003043
reed@android.com8a1c16f2008-12-17 15:59:43 +00003044 matrix.setTranslate(hOffset, vOffset);
3045 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3046}
3047
reed@android.comf76bacf2009-05-13 14:00:33 +00003048///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003049
3050/**
3051 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3052 * against the playback cost of recursing into the subpicture to get at its actual ops.
3053 *
3054 * For now we pick a conservatively small value, though measurement (and other heuristics like
3055 * the type of ops contained) may justify changing this value.
3056 */
3057#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003058
reedd5fa1a42014-08-09 11:08:05 -07003059void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003060 RETURN_ON_NULL(picture);
3061
reed1c2c4412015-04-30 13:09:24 -07003062 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003063 if (matrix && matrix->isIdentity()) {
3064 matrix = nullptr;
3065 }
3066 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3067 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3068 picture->playback(this);
3069 } else {
3070 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003071 }
3072}
robertphillips9b14f262014-06-04 05:40:44 -07003073
reedd5fa1a42014-08-09 11:08:05 -07003074void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3075 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003076 if (!paint || paint->canComputeFastBounds()) {
3077 SkRect bounds = picture->cullRect();
3078 if (paint) {
3079 paint->computeFastBounds(bounds, &bounds);
3080 }
3081 if (matrix) {
3082 matrix->mapRect(&bounds);
3083 }
3084 if (this->quickReject(bounds)) {
3085 return;
3086 }
3087 }
3088
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003089 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003090 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003091}
3092
vjiaoblack95302da2016-07-21 10:25:54 -07003093#ifdef SK_EXPERIMENTAL_SHADOWING
3094void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3095 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003096 const SkPaint* paint,
3097 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003098 RETURN_ON_NULL(picture);
3099
3100 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3101
vjiaoblacke6f5d562016-08-25 06:30:23 -07003102 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003103}
3104
3105void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3106 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003107 const SkPaint* paint,
3108 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003109 if (!paint || paint->canComputeFastBounds()) {
3110 SkRect bounds = picture->cullRect();
3111 if (paint) {
3112 paint->computeFastBounds(bounds, &bounds);
3113 }
3114 if (matrix) {
3115 matrix->mapRect(&bounds);
3116 }
3117 if (this->quickReject(bounds)) {
3118 return;
3119 }
3120 }
3121
3122 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3123
vjiaoblacke6f5d562016-08-25 06:30:23 -07003124 sk_sp<SkImage> povDepthMap;
3125 sk_sp<SkImage> diffuseMap;
3126
vjiaoblack904527d2016-08-09 09:32:09 -07003127 // povDepthMap
3128 {
3129 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003130 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3131 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003132 sk_sp<SkLights> povLight = builder.finish();
3133
3134 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3135 picture->cullRect().height(),
3136 kBGRA_8888_SkColorType,
3137 kOpaque_SkAlphaType);
3138
3139 // Create a new surface (that matches the backend of canvas)
3140 // to create the povDepthMap
3141 sk_sp<SkSurface> surf(this->makeSurface(info));
3142
3143 // Wrap another SPFCanvas around the surface
3144 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3145 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3146
3147 // set the depth map canvas to have the light as the user's POV
3148 depthMapCanvas->setLights(std::move(povLight));
3149
3150 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003151 povDepthMap = surf->makeImageSnapshot();
3152 }
3153
3154 // diffuseMap
3155 {
3156 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3157 picture->cullRect().height(),
3158 kBGRA_8888_SkColorType,
3159 kOpaque_SkAlphaType);
3160
3161 sk_sp<SkSurface> surf(this->makeSurface(info));
3162 surf->getCanvas()->drawPicture(picture);
3163
3164 diffuseMap = surf->makeImageSnapshot();
3165 }
vjiaoblack904527d2016-08-09 09:32:09 -07003166
3167 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3168 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003169 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3170 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003171
3172 // TODO: pass the depth to the shader in vertices, or uniforms
3173 // so we don't have to render depth and color separately
3174 for (int i = 0; i < fLights->numLights(); ++i) {
3175 // skip over ambient lights; they don't cast shadows
3176 // lights that have shadow maps do not need updating (because lights are immutable)
3177 sk_sp<SkImage> depthMap;
3178 SkISize shMapSize;
3179
3180 if (fLights->light(i).getShadowMap() != nullptr) {
3181 continue;
3182 }
3183
3184 if (fLights->light(i).isRadial()) {
3185 shMapSize.fHeight = 1;
3186 shMapSize.fWidth = (int) picture->cullRect().width();
3187
3188 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3189 kBGRA_8888_SkColorType,
3190 kOpaque_SkAlphaType);
3191
3192 // Create new surface (that matches the backend of canvas)
3193 // for each shadow map
3194 sk_sp<SkSurface> surf(this->makeSurface(info));
3195
3196 // Wrap another SPFCanvas around the surface
3197 SkCanvas* depthMapCanvas = surf->getCanvas();
3198
3199 SkLights::Builder builder;
3200 builder.add(fLights->light(i));
3201 sk_sp<SkLights> curLight = builder.finish();
3202
3203 sk_sp<SkShader> shadowMapShader;
3204 shadowMapShader = SkRadialShadowMapShader::Make(
3205 povDepthShader, curLight,
3206 (int) picture->cullRect().width(),
3207 (int) picture->cullRect().height());
3208
3209 SkPaint shadowMapPaint;
3210 shadowMapPaint.setShader(std::move(shadowMapShader));
3211
3212 depthMapCanvas->setLights(curLight);
3213
3214 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3215 diffuseMap->height()),
3216 shadowMapPaint);
3217
3218 depthMap = surf->makeImageSnapshot();
3219
3220 } else {
3221 // TODO: compute the correct size of the depth map from the light properties
3222 // TODO: maybe add a kDepth_8_SkColorType
3223 // TODO: find actual max depth of picture
3224 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3225 fLights->light(i), 255,
3226 (int) picture->cullRect().width(),
3227 (int) picture->cullRect().height());
3228
3229 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3230 kBGRA_8888_SkColorType,
3231 kOpaque_SkAlphaType);
3232
3233 // Create a new surface (that matches the backend of canvas)
3234 // for each shadow map
3235 sk_sp<SkSurface> surf(this->makeSurface(info));
3236
3237 // Wrap another SPFCanvas around the surface
3238 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3239 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3240 depthMapCanvas->setShadowParams(params);
3241
3242 // set the depth map canvas to have the light we're drawing.
3243 SkLights::Builder builder;
3244 builder.add(fLights->light(i));
3245 sk_sp<SkLights> curLight = builder.finish();
3246 depthMapCanvas->setLights(std::move(curLight));
3247
3248 depthMapCanvas->drawPicture(picture);
3249 depthMap = surf->makeImageSnapshot();
3250 }
3251
3252 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3253 fLights->light(i).setShadowMap(std::move(depthMap));
3254 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3255 // we blur the variance map
3256 SkPaint blurPaint;
3257 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3258 params.fShadowRadius, nullptr));
3259
3260 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3261 kBGRA_8888_SkColorType,
3262 kOpaque_SkAlphaType);
3263
3264 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3265
3266 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3267
3268 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3269 }
3270 }
3271
3272 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003273 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3274 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003275 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003276 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003277 diffuseMap->height(),
3278 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003279
3280 shadowPaint.setShader(shadowShader);
3281
3282 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003283}
3284#endif
3285
reed@android.com8a1c16f2008-12-17 15:59:43 +00003286///////////////////////////////////////////////////////////////////////////////
3287///////////////////////////////////////////////////////////////////////////////
3288
reed3aafe112016-08-18 12:45:34 -07003289SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003290 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003291
3292 SkASSERT(canvas);
3293
reed3aafe112016-08-18 12:45:34 -07003294 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003295 fDone = !fImpl->next();
3296}
3297
3298SkCanvas::LayerIter::~LayerIter() {
3299 fImpl->~SkDrawIter();
3300}
3301
3302void SkCanvas::LayerIter::next() {
3303 fDone = !fImpl->next();
3304}
3305
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003306SkBaseDevice* SkCanvas::LayerIter::device() const {
Mike Reed99330ba2017-02-22 11:01:08 -05003307 return fImpl->fDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003308}
3309
3310const SkMatrix& SkCanvas::LayerIter::matrix() const {
3311 return fImpl->getMatrix();
3312}
3313
3314const SkPaint& SkCanvas::LayerIter::paint() const {
3315 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003316 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003317 paint = &fDefaultPaint;
3318 }
3319 return *paint;
3320}
3321
reed1e7f5e72016-04-27 07:49:17 -07003322const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003323int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3324int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003325
3326///////////////////////////////////////////////////////////////////////////////
3327
fmalitac3b589a2014-06-05 12:40:07 -07003328SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003329
3330///////////////////////////////////////////////////////////////////////////////
3331
3332static bool supported_for_raster_canvas(const SkImageInfo& info) {
3333 switch (info.alphaType()) {
3334 case kPremul_SkAlphaType:
3335 case kOpaque_SkAlphaType:
3336 break;
3337 default:
3338 return false;
3339 }
3340
3341 switch (info.colorType()) {
3342 case kAlpha_8_SkColorType:
3343 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003344 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003345 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003346 break;
3347 default:
3348 return false;
3349 }
3350
3351 return true;
3352}
3353
Mike Reed5df49342016-11-12 08:06:55 -06003354std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3355 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003356 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003357 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003358 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003359
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003360 SkBitmap bitmap;
3361 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003362 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003363 }
Mike Reed5df49342016-11-12 08:06:55 -06003364 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003365}
reedd5fa1a42014-08-09 11:08:05 -07003366
3367///////////////////////////////////////////////////////////////////////////////
3368
3369SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003370 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003371 : fCanvas(canvas)
3372 , fSaveCount(canvas->getSaveCount())
3373{
bsalomon49f085d2014-09-05 13:34:00 -07003374 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003375 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003376 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003377 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003378 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003379 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003380 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003381 canvas->save();
3382 }
mtklein6cfa73a2014-08-13 13:33:49 -07003383
bsalomon49f085d2014-09-05 13:34:00 -07003384 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003385 canvas->concat(*matrix);
3386 }
3387}
3388
3389SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3390 fCanvas->restoreToCount(fSaveCount);
3391}
reede8f30622016-03-23 18:59:25 -07003392
Florin Malitaee424ac2016-12-01 12:47:59 -05003393///////////////////////////////////////////////////////////////////////////////
3394
3395SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3396 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3397
Florin Malita439ace92016-12-02 12:05:41 -05003398SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3399 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3400
Florin Malitaee424ac2016-12-01 12:47:59 -05003401SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3402 (void)this->INHERITED::getSaveLayerStrategy(rec);
3403 return kNoLayer_SaveLayerStrategy;
3404}
3405
3406///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003407
reed73603f32016-09-20 08:42:38 -07003408static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3409static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3410static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3411static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3412static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3413static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003414
3415///////////////////////////////////////////////////////////////////////////////////////////////////
3416
3417SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3418 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3419 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3420 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3421 SkIPoint origin = dev->getOrigin();
3422 SkMatrix ctm = this->getTotalMatrix();
3423 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3424
3425 SkIRect clip = fMCRec->fRasterClip.getBounds();
3426 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003427 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003428 clip.setEmpty();
3429 }
3430
3431 fAllocator->updateHandle(handle, ctm, clip);
3432 return handle;
3433 }
3434 return nullptr;
3435}
3436
3437static bool install(SkBitmap* bm, const SkImageInfo& info,
3438 const SkRasterHandleAllocator::Rec& rec) {
3439 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3440 rec.fReleaseProc, rec.fReleaseCtx);
3441}
3442
3443SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3444 SkBitmap* bm) {
3445 SkRasterHandleAllocator::Rec rec;
3446 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3447 return nullptr;
3448 }
3449 return rec.fHandle;
3450}
3451
3452std::unique_ptr<SkCanvas>
3453SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3454 const SkImageInfo& info, const Rec* rec) {
3455 if (!alloc || !supported_for_raster_canvas(info)) {
3456 return nullptr;
3457 }
3458
3459 SkBitmap bm;
3460 Handle hndl;
3461
3462 if (rec) {
3463 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3464 } else {
3465 hndl = alloc->allocBitmap(info, &bm);
3466 }
3467 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3468}