blob: 64ef348e1377455fcb2ce6a5e8f439b78c1179d7 [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
Mike Reed986480a2017-01-13 22:43:16 +00008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070017#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080018#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070019#include "SkImageFilter.h"
20#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070021#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060022#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050025#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070026#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070027#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070028#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000029#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070030#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000031#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050032#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000033#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070034#include "SkShadowPaintFilterCanvas.h"
35#include "SkShadowShader.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000036#include "SkSmallAllocator.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@google.com4b226022011-01-11 18:32:13 +0000233
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 totalClip.translate(-x, -y, &fClip);
235 }
236
reed@google.com045e62d2011-10-24 12:19:46 +0000237 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238
239 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000242 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243 SkRegion::kDifference_Op);
244 }
reed@google.com4b226022011-01-11 18:32:13 +0000245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246#ifdef SK_DEBUG
247 if (!fClip.isEmpty()) {
248 SkIRect deviceR;
249 deviceR.set(0, 0, width, height);
250 SkASSERT(deviceR.contains(fClip.getBounds()));
251 }
252#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000253 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254};
255
256/* This is the record we keep for each save/restore level in the stack.
257 Since a level optionally copies the matrix and/or stack, we have pointers
258 for these fields. If the value is copied for this level, the copy is
259 stored in the ...Storage field, and the pointer points to that. If the
260 value is not copied for this level, we ignore ...Storage, and just point
261 at the corresponding value in the previous level in the stack.
262*/
263class SkCanvas::MCRec {
264public:
reed1f836ee2014-07-07 07:49:34 -0700265 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700266 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267 /* If there are any layers in the stack, this points to the top-most
268 one that is at or below this level in the stack (so we know what
269 bitmap/device to draw into from this level. This value is NOT
270 reference counted, since the real owner is either our fLayer field,
271 or a previous one in a lower level.)
272 */
reed2ff1fce2014-12-11 07:07:37 -0800273 DeviceCM* fTopLayer;
274 SkRasterClip fRasterClip;
275 SkMatrix fMatrix;
276 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277
vjiaoblacke5de1302016-07-13 14:05:28 -0700278 // This is the current cumulative depth (aggregate of all done translateZ calls)
279 SkScalar fCurDrawDepth;
280
reedd9544982014-09-09 18:46:22 -0700281 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700282 fFilter = nullptr;
283 fLayer = nullptr;
284 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800285 fMatrix.reset();
286 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700287 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700288
reedd9544982014-09-09 18:46:22 -0700289 // don't bother initializing fNext
290 inc_rec();
291 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700292 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
293 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700294 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700295 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700296 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800297 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700298
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299 // don't bother initializing fNext
300 inc_rec();
301 }
302 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000303 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700304 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305 dec_rec();
306 }
mtkleinfeaadee2015-04-08 11:25:48 -0700307
308 void reset(const SkIRect& bounds) {
309 SkASSERT(fLayer);
310 SkASSERT(fDeferredSaveCount == 0);
311
312 fMatrix.reset();
313 fRasterClip.setRect(bounds);
314 fLayer->reset(bounds);
315 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316};
317
reed02f9ed72016-09-06 09:06:18 -0700318static SkIRect compute_device_bounds(SkBaseDevice* device) {
319 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
320 device->width(), device->height());
321}
322
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323class SkDrawIter : public SkDraw {
324public:
reed3aafe112016-08-18 12:45:34 -0700325 SkDrawIter(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000326 canvas->updateDeviceCMCache();
327
bungeman6bd52842016-10-27 09:30:08 -0700328 fClipStack = canvas->getClipStack();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700330
331 fMultiDeviceCS = nullptr;
332 if (fCurrLayer->fNext) {
bungeman6bd52842016-10-27 09:30:08 -0700333 fMultiDeviceCS = canvas->fClipStack.get();
reed02f9ed72016-09-06 09:06:18 -0700334 fMultiDeviceCS->save();
335 }
336 }
337
338 ~SkDrawIter() {
339 if (fMultiDeviceCS) {
340 fMultiDeviceCS->restore();
341 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 }
reed@google.com4b226022011-01-11 18:32:13 +0000343
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700345 if (fMultiDeviceCS && fDevice) {
346 // remove the previous device's bounds
Mike Reedc1f77742016-12-09 09:00:50 -0500347 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), kDifference_SkClipOp);
reed02f9ed72016-09-06 09:06:18 -0700348 }
349
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700351 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
352 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 }
354
reed@google.comf68c5e22012-02-24 16:38:58 +0000355 const DeviceCM* rec = fCurrLayer;
356 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357
358 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000359 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700361 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700362 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700363 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000365 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366
367 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700368 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000369
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 return true;
371 }
372 return false;
373 }
reed@google.com4b226022011-01-11 18:32:13 +0000374
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000375 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700376 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000377 int getX() const { return fDevice->getOrigin().x(); }
378 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000381
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383 const DeviceCM* fCurrLayer;
384 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700385 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000386
387 typedef SkDraw INHERITED;
388};
389
Mike Reed7627fa52017-02-08 10:07:53 -0500390#define FOR_EACH_TOP_DEVICE( code ) \
391 do { \
392 DeviceCM* layer = fMCRec->fTopLayer; \
393 while (layer) { \
394 SkBaseDevice* device = layer->fDevice; \
395 code; \
396 layer = layer->fNext; \
397 } \
398 } while (0)
399
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400/////////////////////////////////////////////////////////////////////////////
401
reeddbc3cef2015-04-29 12:18:57 -0700402static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
403 return lazy->isValid() ? lazy->get() : lazy->set(orig);
404}
405
406/**
407 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700408 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700409 */
reedd053ce92016-03-22 10:17:23 -0700410static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700411 SkImageFilter* imgf = paint.getImageFilter();
412 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700413 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700414 }
415
reedd053ce92016-03-22 10:17:23 -0700416 SkColorFilter* imgCFPtr;
417 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700418 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700419 }
reedd053ce92016-03-22 10:17:23 -0700420 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700421
422 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700423 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700424 // there is no existing paint colorfilter, so we can just return the imagefilter's
425 return imgCF;
426 }
427
428 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
429 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700430 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700431}
432
senorblanco87e066e2015-10-28 11:23:36 -0700433/**
434 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
435 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
436 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
437 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
438 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
439 * conservative "effective" bounds based on the settings in the paint... with one exception. This
440 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
441 * deliberately ignored.
442 */
443static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
444 const SkRect& rawBounds,
445 SkRect* storage) {
446 SkPaint tmpUnfiltered(paint);
447 tmpUnfiltered.setImageFilter(nullptr);
448 if (tmpUnfiltered.canComputeFastBounds()) {
449 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
450 } else {
451 return rawBounds;
452 }
453}
454
reed@android.com8a1c16f2008-12-17 15:59:43 +0000455class AutoDrawLooper {
456public:
senorblanco87e066e2015-10-28 11:23:36 -0700457 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
458 // paint. It's used to determine the size of the offscreen layer for filters.
459 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700460 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700461 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000462 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800463#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000464 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800465#else
466 fFilter = nullptr;
467#endif
reed4a8126e2014-09-22 07:29:03 -0700468 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000469 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700470 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000471 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000472
reedd053ce92016-03-22 10:17:23 -0700473 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700474 if (simplifiedCF) {
475 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700476 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700477 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700478 fPaint = paint;
479 }
480
481 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700482 /**
483 * We implement ImageFilters for a given draw by creating a layer, then applying the
484 * imagefilter to the pixels of that layer (its backing surface/image), and then
485 * we call restore() to xfer that layer to the main canvas.
486 *
487 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
488 * 2. Generate the src pixels:
489 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
490 * return (fPaint). We then draw the primitive (using srcover) into a cleared
491 * buffer/surface.
492 * 3. Restore the layer created in #1
493 * The imagefilter is passed the buffer/surface from the layer (now filled with the
494 * src pixels of the primitive). It returns a new "filtered" buffer, which we
495 * draw onto the previous layer using the xfermode from the original paint.
496 */
reed@google.com8926b162012-03-23 15:36:36 +0000497 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500498 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700499 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700500 SkRect storage;
501 if (rawBounds) {
502 // Make rawBounds include all paint outsets except for those due to image filters.
503 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
504 }
reedbfd5f172016-01-07 11:28:08 -0800505 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700506 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700507 fTempLayerForImageFilter = true;
508 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000509 }
510
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000511 if (SkDrawLooper* looper = paint.getLooper()) {
herbbf6d80a2016-11-15 06:26:56 -0800512 fLooperContext = fLooperContextAllocator.createWithIniter(
513 looper->contextSize(),
514 [&](void* buffer) {
515 return looper->createContext(canvas, buffer);
516 });
reed@google.com129ec222012-05-15 13:24:09 +0000517 fIsSimple = false;
518 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700519 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000520 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700521 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000522 }
523 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000524
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700526 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000527 fCanvas->internalRestore();
528 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000529 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000531
reed@google.com4e2b3d32011-04-07 14:18:59 +0000532 const SkPaint& paint() const {
533 SkASSERT(fPaint);
534 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000535 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000536
reed@google.com129ec222012-05-15 13:24:09 +0000537 bool next(SkDrawFilter::Type drawType) {
538 if (fDone) {
539 return false;
540 } else if (fIsSimple) {
541 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000542 return !fPaint->nothingToDraw();
543 } else {
544 return this->doNext(drawType);
545 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000546 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000547
reed@android.com8a1c16f2008-12-17 15:59:43 +0000548private:
reeddbc3cef2015-04-29 12:18:57 -0700549 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
550 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000551 SkCanvas* fCanvas;
552 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000553 SkDrawFilter* fFilter;
554 const SkPaint* fPaint;
555 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700556 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000557 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000558 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000559 SkDrawLooper::Context* fLooperContext;
560 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000561
562 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563};
564
reed@google.com129ec222012-05-15 13:24:09 +0000565bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700566 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000567 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700568 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000569
reeddbc3cef2015-04-29 12:18:57 -0700570 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
571 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000572
reed5c476fb2015-04-20 08:04:21 -0700573 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700574 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700575 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000576 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000577
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000578 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000579 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000580 return false;
581 }
582 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000583 if (!fFilter->filter(paint, drawType)) {
584 fDone = true;
585 return false;
586 }
halcanary96fcdcc2015-08-27 07:41:13 -0700587 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000588 // no looper means we only draw once
589 fDone = true;
590 }
591 }
592 fPaint = paint;
593
594 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000595 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000596 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000597 }
598
599 // call this after any possible paint modifiers
600 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700601 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000602 return false;
603 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000604 return true;
605}
606
reed@android.com8a1c16f2008-12-17 15:59:43 +0000607////////// macros to place around the internal draw calls //////////////////
608
reed3aafe112016-08-18 12:45:34 -0700609#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
610 this->predrawNotify(); \
611 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
612 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800613 SkDrawIter iter(this);
614
615
reed@google.com8926b162012-03-23 15:36:36 +0000616#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000617 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700618 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000619 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000620 SkDrawIter iter(this);
621
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000622#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000623 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700624 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000625 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000626 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000627
reedc83a2972015-07-16 07:40:45 -0700628#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
629 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700630 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700631 while (looper.next(type)) { \
632 SkDrawIter iter(this);
633
reed@google.com4e2b3d32011-04-07 14:18:59 +0000634#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000635
636////////////////////////////////////////////////////////////////////////////
637
msarettfbfa2582016-08-12 08:29:08 -0700638static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
639 if (bounds.isEmpty()) {
640 return SkRect::MakeEmpty();
641 }
642
643 // Expand bounds out by 1 in case we are anti-aliasing. We store the
644 // bounds as floats to enable a faster quick reject implementation.
645 SkRect dst;
646 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
647 return dst;
648}
649
mtkleinfeaadee2015-04-08 11:25:48 -0700650void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
651 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700652 fClipStack->reset();
653 fMCRec->reset(bounds);
654
655 // We're peering through a lot of structs here. Only at this scope do we
656 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
657 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700658 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700659 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700660}
661
reedd9544982014-09-09 18:46:22 -0700662SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800663 if (device && device->forceConservativeRasterClip()) {
664 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
665 }
666 // Since init() is only called once by our constructors, it is safe to perform this
667 // const-cast.
668 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
669
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000670 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700671 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800672 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700673 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700674#ifdef SK_EXPERIMENTAL_SHADOWING
675 fLights = nullptr;
676#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677
halcanary385fe4d2015-08-26 13:07:48 -0700678 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700679
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700681 new (fMCRec) MCRec(fConservativeRasterClip);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500682 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700683 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684
reeda499f902015-05-01 09:34:31 -0700685 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
686 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700687 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700688 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700689
reed@android.com8a1c16f2008-12-17 15:59:43 +0000690 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691
halcanary96fcdcc2015-08-27 07:41:13 -0700692 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000693
reedf92c8662014-08-18 08:02:43 -0700694 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700695 // The root device and the canvas should always have the same pixel geometry
696 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700697 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800698 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700699 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700700 }
msarettfbfa2582016-08-12 08:29:08 -0700701
reedf92c8662014-08-18 08:02:43 -0700702 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000703}
704
reed@google.comcde92112011-07-06 20:00:52 +0000705SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000706 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700707 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800708 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000709{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000710 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000711
halcanary96fcdcc2015-08-27 07:41:13 -0700712 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000713}
714
reedd9544982014-09-09 18:46:22 -0700715static SkBitmap make_nopixels(int width, int height) {
716 SkBitmap bitmap;
717 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
718 return bitmap;
719}
720
721class SkNoPixelsBitmapDevice : public SkBitmapDevice {
722public:
robertphillipsfcf78292015-06-19 11:49:52 -0700723 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
724 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800725 {
726 this->setOrigin(bounds.x(), bounds.y());
727 }
reedd9544982014-09-09 18:46:22 -0700728
729private:
piotaixrb5fae932014-09-24 13:03:30 -0700730
reedd9544982014-09-09 18:46:22 -0700731 typedef SkBitmapDevice INHERITED;
732};
733
reed96a857e2015-01-25 10:33:58 -0800734SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000735 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800736 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800737 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000738{
739 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700740
halcanary385fe4d2015-08-26 13:07:48 -0700741 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
742 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700743}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000744
reed78e27682014-11-19 08:04:34 -0800745SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700746 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700747 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800748 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700749{
750 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700751
halcanary385fe4d2015-08-26 13:07:48 -0700752 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700753}
754
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000755SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000756 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700757 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800758 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000759{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000760 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700761
reedd9544982014-09-09 18:46:22 -0700762 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000763}
764
robertphillipsfcf78292015-06-19 11:49:52 -0700765SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
766 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700767 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800768 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700769{
770 inc_canvas();
771
772 this->init(device, flags);
773}
774
reed4a8126e2014-09-22 07:29:03 -0700775SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700776 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700777 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800778 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700779{
780 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700781
Hal Canary704cd322016-11-07 14:13:52 -0500782 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
783 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700784}
reed29c857d2014-09-21 10:25:07 -0700785
Mike Reed356f7c22017-01-10 11:58:39 -0500786SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
787 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700788 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
789 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500790 , fAllocator(std::move(alloc))
reed42b73eb2015-11-20 13:42:42 -0800791 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700792{
793 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700794
Mike Reed356f7c22017-01-10 11:58:39 -0500795 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500796 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000797}
798
Mike Reed356f7c22017-01-10 11:58:39 -0500799SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
800
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801SkCanvas::~SkCanvas() {
802 // free up the contents of our deque
803 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000804
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805 this->internalRestore(); // restore the last, since we're going away
806
halcanary385fe4d2015-08-26 13:07:48 -0700807 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000808
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809 dec_canvas();
810}
811
fmalita53d9f1c2016-01-25 06:23:54 -0800812#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813SkDrawFilter* SkCanvas::getDrawFilter() const {
814 return fMCRec->fFilter;
815}
816
817SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700818 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000819 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
820 return filter;
821}
fmalita77650002016-01-21 18:47:11 -0800822#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000824SkMetaData& SkCanvas::getMetaData() {
825 // metadata users are rare, so we lazily allocate it. If that changes we
826 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700827 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000828 fMetaData = new SkMetaData;
829 }
830 return *fMetaData;
831}
832
reed@android.com8a1c16f2008-12-17 15:59:43 +0000833///////////////////////////////////////////////////////////////////////////////
834
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000835void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700836 this->onFlush();
837}
838
839void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000840 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000841 if (device) {
842 device->flush();
843 }
844}
845
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000846SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000847 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000848 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
849}
850
senorblancoafc7cce2016-02-02 18:44:15 -0800851SkIRect SkCanvas::getTopLayerBounds() const {
852 SkBaseDevice* d = this->getTopDevice();
853 if (!d) {
854 return SkIRect::MakeEmpty();
855 }
856 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
857}
858
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000859SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000860 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000861 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000862 SkASSERT(rec && rec->fLayer);
863 return rec->fLayer->fDevice;
864}
865
Florin Malita0ed3b642017-01-13 16:56:38 +0000866SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000867 return fMCRec->fTopLayer->fDevice;
868}
869
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000870bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000871 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700872 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700873 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000874 return false;
875 }
876 weAllocated = true;
877 }
878
reedcf01e312015-05-23 19:14:51 -0700879 SkAutoPixmapUnlock unlocker;
880 if (bitmap->requestLock(&unlocker)) {
881 const SkPixmap& pm = unlocker.pixmap();
882 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
883 return true;
884 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000885 }
886
887 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500888 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000889 }
890 return false;
891}
reed@google.com51df9e32010-12-23 19:29:18 +0000892
bsalomon@google.comc6980972011-11-02 19:57:21 +0000893bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000894 SkIRect r = srcRect;
895 const SkISize size = this->getBaseLayerSize();
896 if (!r.intersect(0, 0, size.width(), size.height())) {
897 bitmap->reset();
898 return false;
899 }
900
reed84825042014-09-02 12:50:45 -0700901 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000902 // bitmap will already be reset.
903 return false;
904 }
905 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
906 bitmap->reset();
907 return false;
908 }
909 return true;
910}
911
reed96472de2014-12-10 09:53:42 -0800912bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000913 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000914 if (!device) {
915 return false;
916 }
mtkleinf0f14112014-12-12 08:46:25 -0800917
Matt Sarett03dd6d52017-01-23 12:15:09 -0500918 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000919}
920
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000921bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700922 SkAutoPixmapUnlock unlocker;
923 if (bitmap.requestLock(&unlocker)) {
924 const SkPixmap& pm = unlocker.pixmap();
925 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000926 }
927 return false;
928}
929
Matt Sarett03dd6d52017-01-23 12:15:09 -0500930bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000931 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000932 SkBaseDevice* device = this->getDevice();
933 if (!device) {
934 return false;
935 }
936
Matt Sarett03dd6d52017-01-23 12:15:09 -0500937 // This check gives us an early out and prevents generation ID churn on the surface.
938 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
939 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
940 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
941 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000942 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000943
Matt Sarett03dd6d52017-01-23 12:15:09 -0500944 // Tell our owning surface to bump its generation ID.
945 const bool completeOverwrite =
946 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700947 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700948
Matt Sarett03dd6d52017-01-23 12:15:09 -0500949 // This can still fail, most notably in the case of a invalid color type or alpha type
950 // conversion. We could pull those checks into this function and avoid the unnecessary
951 // generation ID bump. But then we would be performing those checks twice, since they
952 // are also necessary at the bitmap/pixmap entry points.
953 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000954}
reed@google.com51df9e32010-12-23 19:29:18 +0000955
reed@android.com8a1c16f2008-12-17 15:59:43 +0000956//////////////////////////////////////////////////////////////////////////////
957
reed@android.com8a1c16f2008-12-17 15:59:43 +0000958void SkCanvas::updateDeviceCMCache() {
959 if (fDeviceCMDirty) {
960 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700961 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000963
halcanary96fcdcc2015-08-27 07:41:13 -0700964 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700965 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000967 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968 do {
reedde6c5312016-09-02 12:10:07 -0700969 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700970 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971 }
972 fDeviceCMDirty = false;
973 }
974}
975
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976///////////////////////////////////////////////////////////////////////////////
977
reed2ff1fce2014-12-11 07:07:37 -0800978void SkCanvas::checkForDeferredSave() {
979 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800980 this->doSave();
981 }
982}
983
reedf0090cb2014-11-26 08:55:51 -0800984int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800985#ifdef SK_DEBUG
986 int count = 0;
987 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
988 for (;;) {
989 const MCRec* rec = (const MCRec*)iter.next();
990 if (!rec) {
991 break;
992 }
993 count += 1 + rec->fDeferredSaveCount;
994 }
995 SkASSERT(count == fSaveCount);
996#endif
997 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800998}
999
1000int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001001 fSaveCount += 1;
1002 fMCRec->fDeferredSaveCount += 1;
1003 return this->getSaveCount() - 1; // return our prev value
1004}
1005
1006void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001007 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001008
1009 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1010 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001011 this->internalSave();
Mike Reed7627fa52017-02-08 10:07:53 -05001012#ifdef SK_USE_DEVICE_CLIPPING
1013 FOR_EACH_TOP_DEVICE(device->save());
1014#endif
reedf0090cb2014-11-26 08:55:51 -08001015}
1016
1017void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001018 if (fMCRec->fDeferredSaveCount > 0) {
1019 SkASSERT(fSaveCount > 1);
1020 fSaveCount -= 1;
1021 fMCRec->fDeferredSaveCount -= 1;
1022 } else {
1023 // check for underflow
1024 if (fMCStack.count() > 1) {
1025 this->willRestore();
1026 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001027 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001028 this->internalRestore();
1029 this->didRestore();
Mike Reed7627fa52017-02-08 10:07:53 -05001030#ifdef SK_USE_DEVICE_CLIPPING
1031 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1032#endif
reed2ff1fce2014-12-11 07:07:37 -08001033 }
reedf0090cb2014-11-26 08:55:51 -08001034 }
1035}
1036
1037void SkCanvas::restoreToCount(int count) {
1038 // sanity check
1039 if (count < 1) {
1040 count = 1;
1041 }
mtkleinf0f14112014-12-12 08:46:25 -08001042
reedf0090cb2014-11-26 08:55:51 -08001043 int n = this->getSaveCount() - count;
1044 for (int i = 0; i < n; ++i) {
1045 this->restore();
1046 }
1047}
1048
reed2ff1fce2014-12-11 07:07:37 -08001049void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001050 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001051 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001052 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001053
reed687fa1c2015-04-07 08:00:56 -07001054 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001055}
1056
reed4960eee2015-12-18 07:09:18 -08001057bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001058 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059}
1060
reed4960eee2015-12-18 07:09:18 -08001061bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001062 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -05001063 SkIRect clipBounds = this->getDeviceClipBounds();
1064 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001065 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001066 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001067
reed96e657d2015-03-10 17:30:07 -07001068 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1069
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001070 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001071 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001072 if (bounds && !imageFilter->canComputeFastBounds()) {
1073 bounds = nullptr;
1074 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001075 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001076 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001077 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001078 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001079
reed96e657d2015-03-10 17:30:07 -07001080 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001081 r.roundOut(&ir);
1082 // early exit if the layer's bounds are clipped out
1083 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001084 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001085 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001086 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001087 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001088 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089 }
1090 } else { // no user bounds, so just use the clip
1091 ir = clipBounds;
1092 }
reed180aec42015-03-11 10:39:04 -07001093 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001094
reed4960eee2015-12-18 07:09:18 -08001095 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001096 // Simplify the current clips since they will be applied properly during restore()
Mike Reedc1f77742016-12-09 09:00:50 -05001097 fClipStack->clipDevRect(ir, kReplace_SkClipOp);
reed180aec42015-03-11 10:39:04 -07001098 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001099 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001100 }
1101
1102 if (intersection) {
1103 *intersection = ir;
1104 }
1105 return true;
1106}
1107
reed4960eee2015-12-18 07:09:18 -08001108
reed4960eee2015-12-18 07:09:18 -08001109int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1110 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001111}
1112
reed70ee31b2015-12-10 13:44:45 -08001113int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001114 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1115}
1116
1117int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1118 SaveLayerRec rec(origRec);
1119 if (gIgnoreSaveLayerBounds) {
1120 rec.fBounds = nullptr;
1121 }
1122 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1123 fSaveCount += 1;
1124 this->internalSaveLayer(rec, strategy);
1125 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001126}
1127
reeda2217ef2016-07-20 06:04:34 -07001128void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1129 SkBaseDevice* dst, const SkMatrix& ctm,
1130 const SkClipStack* clipStack) {
1131 SkDraw draw;
1132 SkRasterClip rc;
1133 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1134 if (!dst->accessPixels(&draw.fDst)) {
1135 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001136 }
reeda2217ef2016-07-20 06:04:34 -07001137 draw.fMatrix = &SkMatrix::I();
1138 draw.fRC = &rc;
1139 draw.fClipStack = clipStack;
1140 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001141
1142 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001143 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001144
1145 int x = src->getOrigin().x() - dst->getOrigin().x();
1146 int y = src->getOrigin().y() - dst->getOrigin().y();
1147 auto special = src->snapSpecial();
1148 if (special) {
1149 dst->drawSpecial(draw, special.get(), x, y, p);
1150 }
robertphillips7354a4b2015-12-16 05:08:27 -08001151}
reed70ee31b2015-12-10 13:44:45 -08001152
reed129ed1c2016-02-22 06:42:31 -08001153static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1154 const SkPaint* paint) {
1155 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1156 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001157 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001158 const bool hasImageFilter = paint && paint->getImageFilter();
1159
1160 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1161 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1162 // force to L32
1163 return SkImageInfo::MakeN32(w, h, alphaType);
1164 } else {
1165 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001166 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001167 }
1168}
1169
reed4960eee2015-12-18 07:09:18 -08001170void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1171 const SkRect* bounds = rec.fBounds;
1172 const SkPaint* paint = rec.fPaint;
1173 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1174
reed8c30a812016-04-20 16:36:51 -07001175 SkLazyPaint lazyP;
1176 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1177 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001178 SkMatrix remainder;
1179 SkSize scale;
1180 /*
1181 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1182 * but they do handle scaling. To accommodate this, we do the following:
1183 *
1184 * 1. Stash off the current CTM
1185 * 2. Decompose the CTM into SCALE and REMAINDER
1186 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1187 * contains the REMAINDER
1188 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1189 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1190 * of the original imagefilter, and draw that (via drawSprite)
1191 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1192 *
1193 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1194 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1195 */
reed96a04f32016-04-25 09:25:15 -07001196 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001197 stashedMatrix.decomposeScale(&scale, &remainder))
1198 {
1199 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1200 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1201 SkPaint* p = lazyP.set(*paint);
1202 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1203 SkFilterQuality::kLow_SkFilterQuality,
1204 sk_ref_sp(imageFilter)));
1205 imageFilter = p->getImageFilter();
1206 paint = p;
1207 }
reed8c30a812016-04-20 16:36:51 -07001208
junov@chromium.orga907ac32012-02-24 21:54:07 +00001209 // do this before we create the layer. We don't call the public save() since
1210 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001211 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001212
1213 fDeviceCMDirty = true;
1214
1215 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001216 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001217 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218 }
1219
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001220 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1221 // the clipRectBounds() call above?
1222 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001223 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001224 }
1225
reed4960eee2015-12-18 07:09:18 -08001226 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001227 SkPixelGeometry geo = fProps.pixelGeometry();
1228 if (paint) {
reed76033be2015-03-14 10:54:31 -07001229 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001230 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001231 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001232 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001233 }
1234 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001235
robertphillips5139e502016-07-19 05:10:40 -07001236 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001237 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001238 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001239 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001240 }
reedb2db8982014-11-13 12:41:02 -08001241
robertphillips5139e502016-07-19 05:10:40 -07001242 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001243 paint);
1244
Hal Canary704cd322016-11-07 14:13:52 -05001245 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001246 {
reed70ee31b2015-12-10 13:44:45 -08001247 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001248 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001249 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001250 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001251 preserveLCDText,
1252 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001253 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1254 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001255 return;
reed61f501f2015-04-29 08:34:00 -07001256 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001257 }
robertphillips5139e502016-07-19 05:10:40 -07001258 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001259
Hal Canary704cd322016-11-07 14:13:52 -05001260 DeviceCM* layer =
1261 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001262
1263 layer->fNext = fMCRec->fTopLayer;
1264 fMCRec->fLayer = layer;
1265 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001266
1267 if (rec.fBackdrop) {
Hal Canary704cd322016-11-07 14:13:52 -05001268 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(),
reeda2217ef2016-07-20 06:04:34 -07001269 fMCRec->fMatrix, this->getClipStack());
1270 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271}
1272
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001273int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001274 if (0xFF == alpha) {
1275 return this->saveLayer(bounds, nullptr);
1276 } else {
1277 SkPaint tmpPaint;
1278 tmpPaint.setAlpha(alpha);
1279 return this->saveLayer(bounds, &tmpPaint);
1280 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001281}
1282
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283void SkCanvas::internalRestore() {
1284 SkASSERT(fMCStack.count() != 0);
1285
1286 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001287
reed687fa1c2015-04-07 08:00:56 -07001288 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001289
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001290 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291 DeviceCM* layer = fMCRec->fLayer; // may be null
1292 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001293 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294
1295 // now do the normal restore()
1296 fMCRec->~MCRec(); // balanced in save()
1297 fMCStack.pop_back();
1298 fMCRec = (MCRec*)fMCStack.back();
1299
1300 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1301 since if we're being recorded, we don't want to record this (the
1302 recorder will have already recorded the restore).
1303 */
bsalomon49f085d2014-09-05 13:34:00 -07001304 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001306 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001307 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001308 // restore what we smashed in internalSaveLayer
1309 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001310 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001312 delete layer;
reedb679ca82015-04-07 04:40:48 -07001313 } else {
1314 // we're at the root
reeda499f902015-05-01 09:34:31 -07001315 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001316 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001317 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001319 }
msarettfbfa2582016-08-12 08:29:08 -07001320
1321 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001322 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001323 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1324 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001325}
1326
reede8f30622016-03-23 18:59:25 -07001327sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001328 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001329 props = &fProps;
1330 }
1331 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001332}
1333
reede8f30622016-03-23 18:59:25 -07001334sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001335 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001336 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001337}
1338
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001339SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001340 return this->onImageInfo();
1341}
1342
1343SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001344 SkBaseDevice* dev = this->getDevice();
1345 if (dev) {
1346 return dev->imageInfo();
1347 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001348 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001349 }
1350}
1351
brianosman898235c2016-04-06 07:38:23 -07001352bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001353 return this->onGetProps(props);
1354}
1355
1356bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001357 SkBaseDevice* dev = this->getDevice();
1358 if (dev) {
1359 if (props) {
1360 *props = fProps;
1361 }
1362 return true;
1363 } else {
1364 return false;
1365 }
1366}
1367
reed6ceeebd2016-03-09 14:26:26 -08001368bool SkCanvas::peekPixels(SkPixmap* pmap) {
1369 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001370}
1371
reed884e97c2015-05-26 11:31:54 -07001372bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001373 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001374 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001375}
1376
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001377void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001378 SkPixmap pmap;
1379 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001380 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001381 }
1382 if (info) {
1383 *info = pmap.info();
1384 }
1385 if (rowBytes) {
1386 *rowBytes = pmap.rowBytes();
1387 }
1388 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001389 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001390 }
reed884e97c2015-05-26 11:31:54 -07001391 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001392}
1393
reed884e97c2015-05-26 11:31:54 -07001394bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001395 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001396 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001397}
1398
reed@android.com8a1c16f2008-12-17 15:59:43 +00001399/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001400
reed7503d602016-07-15 14:23:29 -07001401void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001402 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001403 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001404 paint = &tmp;
1405 }
reed@google.com4b226022011-01-11 18:32:13 +00001406
reed@google.com8926b162012-03-23 15:36:36 +00001407 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001408
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001410 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001411 paint = &looper.paint();
1412 SkImageFilter* filter = paint->getImageFilter();
1413 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001414 if (filter) {
1415 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1416 if (specialImage) {
1417 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1418 }
reed@google.com76dd2772012-01-05 21:15:07 +00001419 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001420 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001421 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422 }
reeda2217ef2016-07-20 06:04:34 -07001423
reed@google.com4e2b3d32011-04-07 14:18:59 +00001424 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001425}
1426
reed32704672015-12-16 08:27:10 -08001427/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001428
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001429void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001430 if (dx || dy) {
1431 this->checkForDeferredSave();
1432 fDeviceCMDirty = true;
1433 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001434
reedfe69b502016-09-12 06:31:48 -07001435 // Translate shouldn't affect the is-scale-translateness of the matrix.
1436 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001437
reedfe69b502016-09-12 06:31:48 -07001438 this->didTranslate(dx,dy);
1439 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001440}
1441
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001442void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001443 SkMatrix m;
1444 m.setScale(sx, sy);
1445 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001446}
1447
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001448void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001449 SkMatrix m;
1450 m.setRotate(degrees);
1451 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001452}
1453
bungeman7438bfc2016-07-12 15:01:19 -07001454void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1455 SkMatrix m;
1456 m.setRotate(degrees, px, py);
1457 this->concat(m);
1458}
1459
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001460void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001461 SkMatrix m;
1462 m.setSkew(sx, sy);
1463 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001464}
1465
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001466void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001467 if (matrix.isIdentity()) {
1468 return;
1469 }
1470
reed2ff1fce2014-12-11 07:07:37 -08001471 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001472 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001473 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001474 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001475
1476#ifdef SK_USE_DEVICE_CLIPPING
1477 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1478#endif
1479
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001480 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001481}
1482
reed8c30a812016-04-20 16:36:51 -07001483void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001484 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001485 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001486 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001487}
1488
1489void SkCanvas::setMatrix(const SkMatrix& matrix) {
1490 this->checkForDeferredSave();
1491 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001492 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001493}
1494
reed@android.com8a1c16f2008-12-17 15:59:43 +00001495void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001496 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001497}
1498
vjiaoblack95302da2016-07-21 10:25:54 -07001499#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001500void SkCanvas::translateZ(SkScalar z) {
1501 this->checkForDeferredSave();
1502 this->fMCRec->fCurDrawDepth += z;
1503 this->didTranslateZ(z);
1504}
1505
1506SkScalar SkCanvas::getZ() const {
1507 return this->fMCRec->fCurDrawDepth;
1508}
1509
vjiaoblack95302da2016-07-21 10:25:54 -07001510void SkCanvas::setLights(sk_sp<SkLights> lights) {
1511 this->fLights = lights;
1512}
1513
1514sk_sp<SkLights> SkCanvas::getLights() const {
1515 return this->fLights;
1516}
1517#endif
1518
reed@android.com8a1c16f2008-12-17 15:59:43 +00001519//////////////////////////////////////////////////////////////////////////////
1520
Mike Reedc1f77742016-12-09 09:00:50 -05001521void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001522 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001523 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1524 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001525}
1526
Mike Reedc1f77742016-12-09 09:00:50 -05001527void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001528 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001529
1530#ifdef SK_USE_DEVICE_CLIPPING
1531 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
1532#endif
1533
reedc64eff52015-11-21 12:39:45 -08001534 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001535 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1536 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1537 isAA);
reedc64eff52015-11-21 12:39:45 -08001538 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001539 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001540}
1541
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001542void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1543 fClipRestrictionRect = rect;
1544 fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
1545 if (!fClipRestrictionRect.isEmpty()) {
1546 this->checkForDeferredSave();
1547 AutoValidateClip avc(this);
1548 fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
1549 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
1550 fDeviceCMDirty = true;
1551 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1552 }
1553}
1554
Mike Reedc1f77742016-12-09 09:00:50 -05001555void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001556 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001557 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001558 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001559 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1560 } else {
1561 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001562 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001563}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001564
Mike Reedc1f77742016-12-09 09:00:50 -05001565void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001566 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001567
Brian Salomona3b45d42016-10-03 11:36:16 -04001568 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001569
Brian Salomona3b45d42016-10-03 11:36:16 -04001570 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001571
1572#ifdef SK_USE_DEVICE_CLIPPING
1573 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
1574#endif
1575
Brian Salomona3b45d42016-10-03 11:36:16 -04001576 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1577 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1578 isAA);
1579 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1580 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001581}
1582
Mike Reedc1f77742016-12-09 09:00:50 -05001583void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001584 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001585 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001586
1587 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1588 SkRect r;
1589 if (path.isRect(&r)) {
1590 this->onClipRect(r, op, edgeStyle);
1591 return;
1592 }
1593 SkRRect rrect;
1594 if (path.isOval(&r)) {
1595 rrect.setOval(r);
1596 this->onClipRRect(rrect, op, edgeStyle);
1597 return;
1598 }
1599 if (path.isRRect(&rrect)) {
1600 this->onClipRRect(rrect, op, edgeStyle);
1601 return;
1602 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001603 }
robertphillips39f05382015-11-24 09:30:12 -08001604
1605 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001606}
1607
Mike Reedc1f77742016-12-09 09:00:50 -05001608void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001609 AutoValidateClip avc(this);
1610
reed@android.com8a1c16f2008-12-17 15:59:43 +00001611 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001612 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001613
1614#ifdef SK_USE_DEVICE_CLIPPING
1615 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
1616#endif
1617
Brian Salomona3b45d42016-10-03 11:36:16 -04001618 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001619
Brian Salomona3b45d42016-10-03 11:36:16 -04001620 const SkPath* rasterClipPath = &path;
1621 const SkMatrix* matrix = &fMCRec->fMatrix;
1622 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001623 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001624 isAA = getClipStack()->asPath(&tempPath);
1625 rasterClipPath = &tempPath;
1626 matrix = &SkMatrix::I();
Mike Reedc1f77742016-12-09 09:00:50 -05001627 op = kReplace_SkClipOp;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001628 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001629 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1630 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001631 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001632}
1633
Mike Reedc1f77742016-12-09 09:00:50 -05001634void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001635 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001636 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001637}
1638
Mike Reedc1f77742016-12-09 09:00:50 -05001639void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001640#ifdef SK_USE_DEVICE_CLIPPING
1641 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
1642#endif
1643
reed@google.com5c3d1472011-02-22 19:12:23 +00001644 AutoValidateClip avc(this);
1645
reed@android.com8a1c16f2008-12-17 15:59:43 +00001646 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001647
reed@google.com5c3d1472011-02-22 19:12:23 +00001648 // todo: signal fClipStack that we have a region, and therefore (I guess)
1649 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001650 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001651
reed73603f32016-09-20 08:42:38 -07001652 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001653 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001654}
1655
reed@google.com819c9212011-02-23 18:56:55 +00001656#ifdef SK_DEBUG
1657void SkCanvas::validateClip() const {
1658 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001659 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001660 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001661 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001662 return;
1663 }
1664
reed@google.com819c9212011-02-23 18:56:55 +00001665 SkIRect ir;
1666 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001667 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001668
reed687fa1c2015-04-07 08:00:56 -07001669 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001670 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001671 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001672 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001673 case SkClipStack::Element::kRect_Type:
1674 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001675 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001676 break;
1677 case SkClipStack::Element::kEmpty_Type:
1678 tmpClip.setEmpty();
1679 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001680 default: {
1681 SkPath path;
1682 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001683 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1684 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001685 break;
1686 }
reed@google.com819c9212011-02-23 18:56:55 +00001687 }
1688 }
reed@google.com819c9212011-02-23 18:56:55 +00001689}
1690#endif
1691
reed@google.com90c07ea2012-04-13 13:50:27 +00001692void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001693 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001694 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001695
halcanary96fcdcc2015-08-27 07:41:13 -07001696 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001697 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001698 }
1699}
1700
reed@google.com5c3d1472011-02-22 19:12:23 +00001701///////////////////////////////////////////////////////////////////////////////
1702
reed@google.com754de5f2014-02-24 19:38:20 +00001703bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001704 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001705}
1706
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001707bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001708 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001709}
1710
msarettfbfa2582016-08-12 08:29:08 -07001711static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1712#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1713 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1714 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1715 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1716 return 0xF != _mm_movemask_ps(mask);
1717#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1718 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1719 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1720 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1721 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1722#else
1723 SkRect devRectAsRect;
1724 SkRect devClipAsRect;
1725 devRect.store(&devRectAsRect.fLeft);
1726 devClip.store(&devClipAsRect.fLeft);
1727 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1728#endif
1729}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001730
msarettfbfa2582016-08-12 08:29:08 -07001731// It's important for this function to not be inlined. Otherwise the compiler will share code
1732// between the fast path and the slow path, resulting in two slow paths.
1733static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1734 const SkMatrix& matrix) {
1735 SkRect deviceRect;
1736 matrix.mapRect(&deviceRect, src);
1737 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1738}
1739
1740bool SkCanvas::quickReject(const SkRect& src) const {
1741#ifdef SK_DEBUG
1742 // Verify that fDeviceClipBounds are set properly.
1743 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001744 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001745 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001746 } else {
msarettfbfa2582016-08-12 08:29:08 -07001747 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001748 }
msarettfbfa2582016-08-12 08:29:08 -07001749
msarett9637ea92016-08-18 14:03:30 -07001750 // Verify that fIsScaleTranslate is set properly.
1751 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001752#endif
1753
msarett9637ea92016-08-18 14:03:30 -07001754 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001755 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1756 }
1757
1758 // We inline the implementation of mapScaleTranslate() for the fast path.
1759 float sx = fMCRec->fMatrix.getScaleX();
1760 float sy = fMCRec->fMatrix.getScaleY();
1761 float tx = fMCRec->fMatrix.getTranslateX();
1762 float ty = fMCRec->fMatrix.getTranslateY();
1763 Sk4f scale(sx, sy, sx, sy);
1764 Sk4f trans(tx, ty, tx, ty);
1765
1766 // Apply matrix.
1767 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1768
1769 // Make sure left < right, top < bottom.
1770 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1771 Sk4f min = Sk4f::Min(ltrb, rblt);
1772 Sk4f max = Sk4f::Max(ltrb, rblt);
1773 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1774 // ARM this sequence generates the fastest (a single instruction).
1775 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1776
1777 // Check if the device rect is NaN or outside the clip.
1778 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001779}
1780
reed@google.com3b3e8952012-08-16 20:53:31 +00001781bool SkCanvas::quickReject(const SkPath& path) const {
1782 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001783}
1784
Mike Reed42e8c532017-01-23 14:09:13 -05001785SkRect SkCanvas::onGetLocalClipBounds() const {
1786 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001787 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001788 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001789 }
1790
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001791 SkMatrix inverse;
1792 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001793 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001794 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001795 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001796
Mike Reed42e8c532017-01-23 14:09:13 -05001797 SkRect bounds;
1798 SkRect r;
1799 // adjust it outwards in case we are antialiasing
1800 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001801
Mike Reed42e8c532017-01-23 14:09:13 -05001802 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1803 ibounds.fRight + inset, ibounds.fBottom + inset);
1804 inverse.mapRect(&bounds, r);
1805 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001806}
1807
Mike Reed42e8c532017-01-23 14:09:13 -05001808SkIRect SkCanvas::onGetDeviceClipBounds() const {
reed1f836ee2014-07-07 07:49:34 -07001809 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001810 if (clip.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001811 return SkIRect::MakeEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001812 }
Mike Reed42e8c532017-01-23 14:09:13 -05001813 return clip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001814}
1815
reed@android.com8a1c16f2008-12-17 15:59:43 +00001816const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001817 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001818}
1819
Mike Reed3726a4a2017-01-19 11:36:41 -05001820void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1821 // we know that ganesh doesn't track the rgn, so ask for its clipstack
1822 if (this->getGrContext()) {
1823 SkPath path;
1824 this->getClipStack()->asPath(&path);
1825 SkISize size = this->getBaseLayerSize();
1826 rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
1827 } else {
1828 *rgn = fMCRec->fRasterClip.forceGetBW();
1829 }
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001830}
1831
Brian Osman11052242016-10-27 14:47:55 -04001832GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001833 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001834 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001835}
1836
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001837GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001838 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001839 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001840}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001841
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001842void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1843 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001844 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001845 if (outer.isEmpty()) {
1846 return;
1847 }
1848 if (inner.isEmpty()) {
1849 this->drawRRect(outer, paint);
1850 return;
1851 }
1852
1853 // We don't have this method (yet), but technically this is what we should
1854 // be able to assert...
1855 // SkASSERT(outer.contains(inner));
1856 //
1857 // For now at least check for containment of bounds
1858 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1859
1860 this->onDrawDRRect(outer, inner, paint);
1861}
1862
reed41af9662015-01-05 07:49:08 -08001863// These need to stop being virtual -- clients need to override the onDraw... versions
1864
1865void SkCanvas::drawPaint(const SkPaint& paint) {
1866 this->onDrawPaint(paint);
1867}
1868
1869void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1870 this->onDrawRect(r, paint);
1871}
1872
msarettdca352e2016-08-26 06:37:45 -07001873void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1874 if (region.isEmpty()) {
1875 return;
1876 }
1877
1878 if (region.isRect()) {
1879 return this->drawIRect(region.getBounds(), paint);
1880 }
1881
1882 this->onDrawRegion(region, paint);
1883}
1884
reed41af9662015-01-05 07:49:08 -08001885void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1886 this->onDrawOval(r, paint);
1887}
1888
1889void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1890 this->onDrawRRect(rrect, paint);
1891}
1892
1893void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1894 this->onDrawPoints(mode, count, pts, paint);
1895}
1896
1897void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001898 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001899 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001900 this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices,
1901 indexCount, paint);
1902}
1903
1904void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint,
1905 uint32_t flags) {
1906 RETURN_ON_NULL(vertices);
1907 this->onDrawVerticesObject(std::move(vertices), mode, paint, flags);
reed41af9662015-01-05 07:49:08 -08001908}
1909
1910void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1911 this->onDrawPath(path, paint);
1912}
1913
reeda85d4d02015-05-06 12:56:48 -07001914void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001915 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001916 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001917}
1918
reede47829b2015-08-06 10:02:53 -07001919void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1920 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001921 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001922 if (dst.isEmpty() || src.isEmpty()) {
1923 return;
1924 }
1925 this->onDrawImageRect(image, &src, dst, paint, constraint);
1926}
reed41af9662015-01-05 07:49:08 -08001927
reed84984ef2015-07-17 07:09:43 -07001928void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1929 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001930 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001931 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001932}
1933
reede47829b2015-08-06 10:02:53 -07001934void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1935 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001936 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001937 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1938 constraint);
1939}
reede47829b2015-08-06 10:02:53 -07001940
reed4c21dc52015-06-25 12:32:03 -07001941void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1942 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001943 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001944 if (dst.isEmpty()) {
1945 return;
1946 }
msarett552bca92016-08-03 06:53:26 -07001947 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1948 this->onDrawImageNine(image, center, dst, paint);
1949 } else {
reede47829b2015-08-06 10:02:53 -07001950 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001951 }
reed4c21dc52015-06-25 12:32:03 -07001952}
1953
msarett16882062016-08-16 09:31:08 -07001954void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1955 const SkPaint* paint) {
1956 RETURN_ON_NULL(image);
1957 if (dst.isEmpty()) {
1958 return;
1959 }
msarett71df2d72016-09-30 12:41:42 -07001960
1961 SkIRect bounds;
1962 Lattice latticePlusBounds = lattice;
1963 if (!latticePlusBounds.fBounds) {
1964 bounds = SkIRect::MakeWH(image->width(), image->height());
1965 latticePlusBounds.fBounds = &bounds;
1966 }
1967
1968 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1969 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001970 } else {
1971 this->drawImageRect(image, dst, paint);
1972 }
1973}
1974
reed41af9662015-01-05 07:49:08 -08001975void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001976 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001977 return;
1978 }
reed41af9662015-01-05 07:49:08 -08001979 this->onDrawBitmap(bitmap, dx, dy, paint);
1980}
1981
reede47829b2015-08-06 10:02:53 -07001982void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001983 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001984 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001985 return;
1986 }
reede47829b2015-08-06 10:02:53 -07001987 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001988}
1989
reed84984ef2015-07-17 07:09:43 -07001990void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1991 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001992 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001993}
1994
reede47829b2015-08-06 10:02:53 -07001995void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1996 SrcRectConstraint constraint) {
1997 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1998 constraint);
1999}
reede47829b2015-08-06 10:02:53 -07002000
reed41af9662015-01-05 07:49:08 -08002001void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2002 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002003 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002004 return;
2005 }
msarett552bca92016-08-03 06:53:26 -07002006 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2007 this->onDrawBitmapNine(bitmap, center, dst, paint);
2008 } else {
reeda5517e22015-07-14 10:54:12 -07002009 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002010 }
reed41af9662015-01-05 07:49:08 -08002011}
2012
msarettc573a402016-08-02 08:05:56 -07002013void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2014 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002015 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002016 return;
2017 }
msarett71df2d72016-09-30 12:41:42 -07002018
2019 SkIRect bounds;
2020 Lattice latticePlusBounds = lattice;
2021 if (!latticePlusBounds.fBounds) {
2022 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2023 latticePlusBounds.fBounds = &bounds;
2024 }
2025
2026 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2027 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002028 } else {
msarett16882062016-08-16 09:31:08 -07002029 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002030 }
msarettc573a402016-08-02 08:05:56 -07002031}
2032
reed71c3c762015-06-24 10:29:17 -07002033void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002034 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002035 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002036 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002037 if (count <= 0) {
2038 return;
2039 }
Joe Gregorioc4859072017-01-20 14:21:27 +00002040 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002041 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002042 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002043}
2044
reedf70b5312016-03-04 16:36:20 -08002045void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2046 if (key) {
2047 this->onDrawAnnotation(rect, key, value);
2048 }
2049}
2050
reede47829b2015-08-06 10:02:53 -07002051void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2052 const SkPaint* paint, SrcRectConstraint constraint) {
2053 if (src) {
2054 this->drawImageRect(image, *src, dst, paint, constraint);
2055 } else {
2056 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2057 dst, paint, constraint);
2058 }
2059}
2060void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2061 const SkPaint* paint, SrcRectConstraint constraint) {
2062 if (src) {
2063 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2064 } else {
2065 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2066 dst, paint, constraint);
2067 }
2068}
2069
tomhudsoncb3bd182016-05-18 07:24:16 -07002070void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2071 SkIRect layer_bounds = this->getTopLayerBounds();
2072 if (matrix) {
2073 *matrix = this->getTotalMatrix();
2074 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2075 }
2076 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05002077 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07002078 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2079 }
2080}
2081
reed@android.com8a1c16f2008-12-17 15:59:43 +00002082//////////////////////////////////////////////////////////////////////////////
2083// These are the virtual drawing methods
2084//////////////////////////////////////////////////////////////////////////////
2085
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002086void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002087 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002088 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2089 }
2090}
2091
reed41af9662015-01-05 07:49:08 -08002092void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002093 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002094 this->internalDrawPaint(paint);
2095}
2096
2097void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002098 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002099
2100 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002101 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002102 }
2103
reed@google.com4e2b3d32011-04-07 14:18:59 +00002104 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002105}
2106
reed41af9662015-01-05 07:49:08 -08002107void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2108 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002109 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002110 if ((long)count <= 0) {
2111 return;
2112 }
2113
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002114 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002115 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002116 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002117 // special-case 2 points (common for drawing a single line)
2118 if (2 == count) {
2119 r.set(pts[0], pts[1]);
2120 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002121 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002122 }
senorblanco87e066e2015-10-28 11:23:36 -07002123 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2124 return;
2125 }
2126 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002127 }
reed@google.coma584aed2012-05-16 14:06:02 +00002128
halcanary96fcdcc2015-08-27 07:41:13 -07002129 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002130
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002131 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002132
reed@android.com8a1c16f2008-12-17 15:59:43 +00002133 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002134 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002135 }
reed@google.com4b226022011-01-11 18:32:13 +00002136
reed@google.com4e2b3d32011-04-07 14:18:59 +00002137 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002138}
2139
reed4a167172016-08-18 17:15:25 -07002140static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2141 return ((intptr_t)paint.getImageFilter() |
2142#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2143 (intptr_t)canvas->getDrawFilter() |
2144#endif
2145 (intptr_t)paint.getLooper() ) != 0;
2146}
2147
reed41af9662015-01-05 07:49:08 -08002148void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002149 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002150 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002151 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002152 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002153 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2154 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2155 SkRect tmp(r);
2156 tmp.sort();
2157
senorblanco87e066e2015-10-28 11:23:36 -07002158 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2159 return;
2160 }
2161 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002162 }
reed@google.com4b226022011-01-11 18:32:13 +00002163
reed4a167172016-08-18 17:15:25 -07002164 if (needs_autodrawlooper(this, paint)) {
2165 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002166
reed4a167172016-08-18 17:15:25 -07002167 while (iter.next()) {
2168 iter.fDevice->drawRect(iter, r, looper.paint());
2169 }
2170
2171 LOOPER_END
2172 } else {
2173 this->predrawNotify(bounds, &paint, false);
2174 SkDrawIter iter(this);
2175 while (iter.next()) {
2176 iter.fDevice->drawRect(iter, r, paint);
2177 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002178 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002179}
2180
msarett44df6512016-08-25 13:54:30 -07002181void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2182 SkRect storage;
2183 SkRect regionRect = SkRect::Make(region.getBounds());
2184 const SkRect* bounds = nullptr;
2185 if (paint.canComputeFastBounds()) {
2186 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2187 return;
2188 }
2189 bounds = &regionRect;
2190 }
2191
2192 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2193
2194 while (iter.next()) {
2195 iter.fDevice->drawRegion(iter, region, looper.paint());
2196 }
2197
2198 LOOPER_END
2199}
2200
reed41af9662015-01-05 07:49:08 -08002201void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002202 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002203 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002204 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002205 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002206 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2207 return;
2208 }
2209 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002210 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002211
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002212 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002213
2214 while (iter.next()) {
2215 iter.fDevice->drawOval(iter, oval, looper.paint());
2216 }
2217
2218 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002219}
2220
bsalomonac3aa242016-08-19 11:25:19 -07002221void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2222 SkScalar sweepAngle, bool useCenter,
2223 const SkPaint& paint) {
2224 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2225 const SkRect* bounds = nullptr;
2226 if (paint.canComputeFastBounds()) {
2227 SkRect storage;
2228 // Note we're using the entire oval as the bounds.
2229 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2230 return;
2231 }
2232 bounds = &oval;
2233 }
2234
2235 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2236
2237 while (iter.next()) {
2238 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2239 }
2240
2241 LOOPER_END
2242}
2243
reed41af9662015-01-05 07:49:08 -08002244void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002245 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002246 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002247 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002248 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002249 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2250 return;
2251 }
2252 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002253 }
2254
2255 if (rrect.isRect()) {
2256 // call the non-virtual version
2257 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002258 return;
2259 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002260 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002261 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2262 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002263 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002264
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002265 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002266
2267 while (iter.next()) {
2268 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2269 }
2270
2271 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002272}
2273
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002274void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2275 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002276 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002277 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002278 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002279 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2280 return;
2281 }
2282 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002283 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002284
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002285 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002286
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002287 while (iter.next()) {
2288 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2289 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002290
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002291 LOOPER_END
2292}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002293
reed41af9662015-01-05 07:49:08 -08002294void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002295 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002296 if (!path.isFinite()) {
2297 return;
2298 }
2299
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002300 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002301 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002302 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002303 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002304 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2305 return;
2306 }
2307 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002309
2310 const SkRect& r = path.getBounds();
2311 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002312 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002313 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002314 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002315 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002316 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002317
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002318 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002319
2320 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002321 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002322 }
2323
reed@google.com4e2b3d32011-04-07 14:18:59 +00002324 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002325}
2326
reed262a71b2015-12-05 13:07:27 -08002327bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002328 if (!paint.getImageFilter()) {
2329 return false;
2330 }
2331
2332 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002333 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002334 return false;
2335 }
2336
2337 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2338 // Once we can filter and the filter will return a result larger than itself, we should be
2339 // able to remove this constraint.
2340 // skbug.com/4526
2341 //
2342 SkPoint pt;
2343 ctm.mapXY(x, y, &pt);
2344 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2345 return ir.contains(fMCRec->fRasterClip.getBounds());
2346}
2347
reeda85d4d02015-05-06 12:56:48 -07002348void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002349 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002350 SkRect bounds = SkRect::MakeXYWH(x, y,
2351 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002352 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002353 SkRect tmp = bounds;
2354 if (paint) {
2355 paint->computeFastBounds(tmp, &tmp);
2356 }
2357 if (this->quickReject(tmp)) {
2358 return;
2359 }
reeda85d4d02015-05-06 12:56:48 -07002360 }
halcanary9d524f22016-03-29 09:03:52 -07002361
reeda85d4d02015-05-06 12:56:48 -07002362 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002363 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002364 paint = lazy.init();
2365 }
reed262a71b2015-12-05 13:07:27 -08002366
reeda2217ef2016-07-20 06:04:34 -07002367 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002368 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2369 *paint);
2370 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002371 special = this->getDevice()->makeSpecial(image);
2372 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002373 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002374 }
2375 }
2376
reed262a71b2015-12-05 13:07:27 -08002377 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2378
reeda85d4d02015-05-06 12:56:48 -07002379 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002380 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002381 if (special) {
2382 SkPoint pt;
2383 iter.fMatrix->mapXY(x, y, &pt);
2384 iter.fDevice->drawSpecial(iter, special.get(),
2385 SkScalarRoundToInt(pt.fX),
2386 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002387 } else {
2388 iter.fDevice->drawImage(iter, image, x, y, pnt);
2389 }
reeda85d4d02015-05-06 12:56:48 -07002390 }
halcanary9d524f22016-03-29 09:03:52 -07002391
reeda85d4d02015-05-06 12:56:48 -07002392 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002393}
2394
reed41af9662015-01-05 07:49:08 -08002395void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002396 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002397 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002398 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002399 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002400 if (paint) {
2401 paint->computeFastBounds(dst, &storage);
2402 }
2403 if (this->quickReject(storage)) {
2404 return;
2405 }
reeda85d4d02015-05-06 12:56:48 -07002406 }
2407 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002408 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002409 paint = lazy.init();
2410 }
halcanary9d524f22016-03-29 09:03:52 -07002411
senorblancoc41e7e12015-12-07 12:51:30 -08002412 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002413 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002414
reeda85d4d02015-05-06 12:56:48 -07002415 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002416 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002417 }
halcanary9d524f22016-03-29 09:03:52 -07002418
reeda85d4d02015-05-06 12:56:48 -07002419 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002420}
2421
reed41af9662015-01-05 07:49:08 -08002422void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002423 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002424 SkDEBUGCODE(bitmap.validate();)
2425
reed33366972015-10-08 09:22:02 -07002426 if (bitmap.drawsNothing()) {
2427 return;
2428 }
2429
2430 SkLazyPaint lazy;
2431 if (nullptr == paint) {
2432 paint = lazy.init();
2433 }
2434
2435 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2436
2437 SkRect storage;
2438 const SkRect* bounds = nullptr;
2439 if (paint->canComputeFastBounds()) {
2440 bitmap.getBounds(&storage);
2441 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002442 SkRect tmp = storage;
2443 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2444 return;
2445 }
2446 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002447 }
reed@google.com4b226022011-01-11 18:32:13 +00002448
reeda2217ef2016-07-20 06:04:34 -07002449 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002450 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2451 *paint);
2452 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002453 special = this->getDevice()->makeSpecial(bitmap);
2454 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002455 drawAsSprite = false;
2456 }
2457 }
2458
reed262a71b2015-12-05 13:07:27 -08002459 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002460
2461 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002462 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002463 if (special) {
reed262a71b2015-12-05 13:07:27 -08002464 SkPoint pt;
2465 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002466 iter.fDevice->drawSpecial(iter, special.get(),
2467 SkScalarRoundToInt(pt.fX),
2468 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002469 } else {
2470 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2471 }
reed33366972015-10-08 09:22:02 -07002472 }
msarettfbfa2582016-08-12 08:29:08 -07002473
reed33366972015-10-08 09:22:02 -07002474 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002475}
2476
reed@google.com9987ec32011-09-07 11:57:52 +00002477// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002478void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002479 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002480 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002481 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482 return;
2483 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002484
halcanary96fcdcc2015-08-27 07:41:13 -07002485 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002486 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002487 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2488 return;
2489 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002490 }
reed@google.com3d608122011-11-21 15:16:16 +00002491
reed@google.com33535f32012-09-25 15:37:50 +00002492 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002493 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002494 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002495 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002496
senorblancoc41e7e12015-12-07 12:51:30 -08002497 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002498 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002499
reed@google.com33535f32012-09-25 15:37:50 +00002500 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002501 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002502 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002503
reed@google.com33535f32012-09-25 15:37:50 +00002504 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002505}
2506
reed41af9662015-01-05 07:49:08 -08002507void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002508 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002509 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002510 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002511 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002512}
2513
reed4c21dc52015-06-25 12:32:03 -07002514void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2515 const SkPaint* paint) {
2516 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002517
halcanary96fcdcc2015-08-27 07:41:13 -07002518 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002519 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002520 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2521 return;
2522 }
reed@google.com3d608122011-11-21 15:16:16 +00002523 }
halcanary9d524f22016-03-29 09:03:52 -07002524
reed4c21dc52015-06-25 12:32:03 -07002525 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002526 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002527 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002528 }
halcanary9d524f22016-03-29 09:03:52 -07002529
senorblancoc41e7e12015-12-07 12:51:30 -08002530 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002531
reed4c21dc52015-06-25 12:32:03 -07002532 while (iter.next()) {
2533 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002534 }
halcanary9d524f22016-03-29 09:03:52 -07002535
reed4c21dc52015-06-25 12:32:03 -07002536 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002537}
2538
reed41af9662015-01-05 07:49:08 -08002539void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2540 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002541 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002542 SkDEBUGCODE(bitmap.validate();)
2543
halcanary96fcdcc2015-08-27 07:41:13 -07002544 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002545 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002546 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2547 return;
2548 }
reed4c21dc52015-06-25 12:32:03 -07002549 }
halcanary9d524f22016-03-29 09:03:52 -07002550
reed4c21dc52015-06-25 12:32:03 -07002551 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002552 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002553 paint = lazy.init();
2554 }
halcanary9d524f22016-03-29 09:03:52 -07002555
senorblancoc41e7e12015-12-07 12:51:30 -08002556 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002557
reed4c21dc52015-06-25 12:32:03 -07002558 while (iter.next()) {
2559 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2560 }
halcanary9d524f22016-03-29 09:03:52 -07002561
reed4c21dc52015-06-25 12:32:03 -07002562 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002563}
2564
msarett16882062016-08-16 09:31:08 -07002565void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2566 const SkPaint* paint) {
2567 if (nullptr == paint || paint->canComputeFastBounds()) {
2568 SkRect storage;
2569 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2570 return;
2571 }
2572 }
2573
2574 SkLazyPaint lazy;
2575 if (nullptr == paint) {
2576 paint = lazy.init();
2577 }
2578
2579 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2580
2581 while (iter.next()) {
2582 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2583 }
2584
2585 LOOPER_END
2586}
2587
2588void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2589 const SkRect& dst, const SkPaint* paint) {
2590 if (nullptr == paint || paint->canComputeFastBounds()) {
2591 SkRect storage;
2592 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2593 return;
2594 }
2595 }
2596
2597 SkLazyPaint lazy;
2598 if (nullptr == paint) {
2599 paint = lazy.init();
2600 }
2601
2602 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2603
2604 while (iter.next()) {
2605 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2606 }
2607
2608 LOOPER_END
2609}
2610
reed@google.comf67e4cf2011-03-15 20:56:58 +00002611class SkDeviceFilteredPaint {
2612public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002613 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002614 uint32_t filteredFlags = device->filterTextFlags(paint);
2615 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002616 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002617 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002618 fPaint = newPaint;
2619 } else {
2620 fPaint = &paint;
2621 }
2622 }
2623
reed@google.comf67e4cf2011-03-15 20:56:58 +00002624 const SkPaint& paint() const { return *fPaint; }
2625
2626private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002627 const SkPaint* fPaint;
2628 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002629};
2630
bungeman@google.com52c748b2011-08-22 21:30:43 +00002631void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2632 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002633 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002634 draw.fDevice->drawRect(draw, r, paint);
2635 } else {
2636 SkPaint p(paint);
Mike Reeda99b6ce2017-02-04 11:04:26 -05002637 p.setStrokeWidth(textSize * paint.getStrokeWidth());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002638 draw.fDevice->drawRect(draw, r, p);
2639 }
2640}
2641
2642void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2643 const char text[], size_t byteLength,
2644 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002645 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002646
2647 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002648 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002649 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002650 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002651 return;
2652 }
2653
2654 SkScalar width = 0;
2655 SkPoint start;
2656
2657 start.set(0, 0); // to avoid warning
2658 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2659 SkPaint::kStrikeThruText_Flag)) {
2660 width = paint.measureText(text, byteLength);
2661
2662 SkScalar offsetX = 0;
2663 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2664 offsetX = SkScalarHalf(width);
2665 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2666 offsetX = width;
2667 }
2668 start.set(x - offsetX, y);
2669 }
2670
2671 if (0 == width) {
2672 return;
2673 }
2674
2675 uint32_t flags = paint.getFlags();
2676
2677 if (flags & (SkPaint::kUnderlineText_Flag |
2678 SkPaint::kStrikeThruText_Flag)) {
2679 SkScalar textSize = paint.getTextSize();
Mike Reeda99b6ce2017-02-04 11:04:26 -05002680 SkScalar height = textSize * kStdUnderline_Thickness;
bungeman@google.com52c748b2011-08-22 21:30:43 +00002681 SkRect r;
2682
2683 r.fLeft = start.fX;
2684 r.fRight = start.fX + width;
2685
2686 if (flags & SkPaint::kUnderlineText_Flag) {
Mike Reeda99b6ce2017-02-04 11:04:26 -05002687 SkScalar offset = textSize * kStdUnderline_Offset + start.fY;
bungeman@google.com52c748b2011-08-22 21:30:43 +00002688 r.fTop = offset;
2689 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002690 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002691 }
2692 if (flags & SkPaint::kStrikeThruText_Flag) {
Mike Reeda99b6ce2017-02-04 11:04:26 -05002693 SkScalar offset = textSize * kStdStrikeThru_Offset + start.fY;
bungeman@google.com52c748b2011-08-22 21:30:43 +00002694 r.fTop = offset;
2695 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002696 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002697 }
2698 }
2699}
2700
reed@google.come0d9ce82014-04-23 04:00:17 +00002701void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2702 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002703 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002704
2705 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002706 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002707 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002708 DrawTextDecorations(iter, dfp.paint(),
2709 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002710 }
2711
reed@google.com4e2b3d32011-04-07 14:18:59 +00002712 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002713}
2714
reed@google.come0d9ce82014-04-23 04:00:17 +00002715void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2716 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002717 SkPoint textOffset = SkPoint::Make(0, 0);
2718
halcanary96fcdcc2015-08-27 07:41:13 -07002719 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002720
reed@android.com8a1c16f2008-12-17 15:59:43 +00002721 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002722 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002723 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002724 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002725 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002726
reed@google.com4e2b3d32011-04-07 14:18:59 +00002727 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002728}
2729
reed@google.come0d9ce82014-04-23 04:00:17 +00002730void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2731 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002732
2733 SkPoint textOffset = SkPoint::Make(0, constY);
2734
halcanary96fcdcc2015-08-27 07:41:13 -07002735 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002736
reed@android.com8a1c16f2008-12-17 15:59:43 +00002737 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002738 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002739 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002740 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002741 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002742
reed@google.com4e2b3d32011-04-07 14:18:59 +00002743 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002744}
2745
reed@google.come0d9ce82014-04-23 04:00:17 +00002746void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2747 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002748 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002749
reed@android.com8a1c16f2008-12-17 15:59:43 +00002750 while (iter.next()) {
2751 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002752 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002754
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002755 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002756}
2757
reed45561a02016-07-07 12:47:17 -07002758void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2759 const SkRect* cullRect, const SkPaint& paint) {
2760 if (cullRect && this->quickReject(*cullRect)) {
2761 return;
2762 }
2763
2764 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2765
2766 while (iter.next()) {
2767 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2768 }
2769
2770 LOOPER_END
2771}
2772
fmalita00d5c2c2014-08-21 08:53:26 -07002773void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2774 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002775
fmalita85d5eb92015-03-04 11:20:12 -08002776 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002777 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002778 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002779 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002780 SkRect tmp;
2781 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2782 return;
2783 }
2784 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002785 }
2786
fmalita024f9962015-03-03 19:08:17 -08002787 // We cannot filter in the looper as we normally do, because the paint is
2788 // incomplete at this point (text-related attributes are embedded within blob run paints).
2789 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002790 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002791
fmalita85d5eb92015-03-04 11:20:12 -08002792 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002793
fmalitaaa1b9122014-08-28 14:32:24 -07002794 while (iter.next()) {
2795 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002796 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002797 }
2798
fmalitaaa1b9122014-08-28 14:32:24 -07002799 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002800
2801 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002802}
2803
reed@google.come0d9ce82014-04-23 04:00:17 +00002804// These will become non-virtual, so they always call the (virtual) onDraw... method
2805void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2806 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002807 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002808 if (byteLength) {
2809 this->onDrawText(text, byteLength, x, y, paint);
2810 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002811}
2812void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2813 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002814 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002815 if (byteLength) {
2816 this->onDrawPosText(text, byteLength, pos, paint);
2817 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002818}
2819void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2820 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002821 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002822 if (byteLength) {
2823 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2824 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002825}
2826void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2827 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002828 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002829 if (byteLength) {
2830 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2831 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002832}
reed45561a02016-07-07 12:47:17 -07002833void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2834 const SkRect* cullRect, const SkPaint& paint) {
2835 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2836 if (byteLength) {
2837 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2838 }
2839}
fmalita00d5c2c2014-08-21 08:53:26 -07002840void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2841 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002842 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002843 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002844 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002845}
reed@google.come0d9ce82014-04-23 04:00:17 +00002846
reed41af9662015-01-05 07:49:08 -08002847void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2848 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002849 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002850 const uint16_t indices[], int indexCount,
2851 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002852 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002853 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002854
reed@android.com8a1c16f2008-12-17 15:59:43 +00002855 while (iter.next()) {
2856 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002857 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002858 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002859 }
reed@google.com4b226022011-01-11 18:32:13 +00002860
reed@google.com4e2b3d32011-04-07 14:18:59 +00002861 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002862}
2863
Brian Salomon199fb872017-02-06 09:41:10 -05002864void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode,
2865 const SkPaint& paint, uint32_t flags) {
2866 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2867 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2868
2869 while (iter.next()) {
2870 // In the common case of one iteration we could std::move vertices here.
2871 iter.fDevice->drawVerticesObject(iter, vertices, bmode, looper.paint(), flags);
2872 }
2873
2874 LOOPER_END
2875}
2876
2877void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode,
2878 const SkPaint& paint, uint32_t flags) {
2879 const SkPoint* texs =
2880 (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords();
2881 const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors();
2882 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs,
2883 colors, mode, vertices->indices(), vertices->indexCount(), paint);
2884}
2885
dandovb3c9d1c2014-08-12 08:34:29 -07002886void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002887 const SkPoint texCoords[4], SkBlendMode bmode,
2888 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002889 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002890 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002891 return;
2892 }
mtklein6cfa73a2014-08-13 13:33:49 -07002893
Mike Reedfaba3712016-11-03 14:45:31 -04002894 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002895}
2896
2897void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002898 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002899 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002900 // Since a patch is always within the convex hull of the control points, we discard it when its
2901 // bounding rectangle is completely outside the current clip.
2902 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002903 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002904 if (this->quickReject(bounds)) {
2905 return;
2906 }
mtklein6cfa73a2014-08-13 13:33:49 -07002907
halcanary96fcdcc2015-08-27 07:41:13 -07002908 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002909
dandovecfff212014-08-04 10:02:00 -07002910 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002911 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002912 }
mtklein6cfa73a2014-08-13 13:33:49 -07002913
dandovecfff212014-08-04 10:02:00 -07002914 LOOPER_END
2915}
2916
reeda8db7282015-07-07 10:22:31 -07002917void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002918 RETURN_ON_NULL(dr);
2919 if (x || y) {
2920 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2921 this->onDrawDrawable(dr, &matrix);
2922 } else {
2923 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002924 }
2925}
2926
reeda8db7282015-07-07 10:22:31 -07002927void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002928 RETURN_ON_NULL(dr);
2929 if (matrix && matrix->isIdentity()) {
2930 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002931 }
reede3b38ce2016-01-08 09:18:44 -08002932 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002933}
2934
2935void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002936 // drawable bounds are no longer reliable (e.g. android displaylist)
2937 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002938 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002939}
2940
reed71c3c762015-06-24 10:29:17 -07002941void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002942 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002943 const SkRect* cull, const SkPaint* paint) {
2944 if (cull && this->quickReject(*cull)) {
2945 return;
2946 }
2947
2948 SkPaint pnt;
2949 if (paint) {
2950 pnt = *paint;
2951 }
halcanary9d524f22016-03-29 09:03:52 -07002952
halcanary96fcdcc2015-08-27 07:41:13 -07002953 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002954 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002955 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002956 }
2957 LOOPER_END
2958}
2959
reedf70b5312016-03-04 16:36:20 -08002960void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2961 SkASSERT(key);
2962
2963 SkPaint paint;
2964 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2965 while (iter.next()) {
2966 iter.fDevice->drawAnnotation(iter, rect, key, value);
2967 }
2968 LOOPER_END
2969}
2970
reed@android.com8a1c16f2008-12-17 15:59:43 +00002971//////////////////////////////////////////////////////////////////////////////
2972// These methods are NOT virtual, and therefore must call back into virtual
2973// methods, rather than actually drawing themselves.
2974//////////////////////////////////////////////////////////////////////////////
2975
reed374772b2016-10-05 17:33:02 -07002976void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002977 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002978 SkPaint paint;
2979
2980 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002981 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002982 this->drawPaint(paint);
2983}
2984
reed374772b2016-10-05 17:33:02 -07002985void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002986 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002987 SkPaint paint;
2988
2989 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002990 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002991 this->drawPaint(paint);
2992}
2993
2994void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002995 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002996 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002997
reed@android.com8a1c16f2008-12-17 15:59:43 +00002998 pt.set(x, y);
2999 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3000}
3001
3002void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08003003 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003004 SkPoint pt;
3005 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00003006
reed@android.com8a1c16f2008-12-17 15:59:43 +00003007 pt.set(x, y);
3008 paint.setColor(color);
3009 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3010}
3011
3012void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
3013 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003014 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003015 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003016
reed@android.com8a1c16f2008-12-17 15:59:43 +00003017 pts[0].set(x0, y0);
3018 pts[1].set(x1, y1);
3019 this->drawPoints(kLines_PointMode, 2, pts, paint);
3020}
3021
3022void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3023 SkScalar right, SkScalar bottom,
3024 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003025 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003026 SkRect r;
3027
3028 r.set(left, top, right, bottom);
3029 this->drawRect(r, paint);
3030}
3031
3032void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3033 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003034 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003035 if (radius < 0) {
3036 radius = 0;
3037 }
3038
3039 SkRect r;
3040 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003041 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003042}
3043
3044void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3045 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003046 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003047 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003048 SkRRect rrect;
3049 rrect.setRectXY(r, rx, ry);
3050 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003051 } else {
3052 this->drawRect(r, paint);
3053 }
3054}
3055
reed@android.com8a1c16f2008-12-17 15:59:43 +00003056void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3057 SkScalar sweepAngle, bool useCenter,
3058 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003059 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003060 if (oval.isEmpty() || !sweepAngle) {
3061 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003062 }
bsalomon21af9ca2016-08-25 12:29:23 -07003063 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003064}
3065
3066void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3067 const SkPath& path, SkScalar hOffset,
3068 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003069 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003070 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003071
reed@android.com8a1c16f2008-12-17 15:59:43 +00003072 matrix.setTranslate(hOffset, vOffset);
3073 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3074}
3075
reed@android.comf76bacf2009-05-13 14:00:33 +00003076///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003077
3078/**
3079 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3080 * against the playback cost of recursing into the subpicture to get at its actual ops.
3081 *
3082 * For now we pick a conservatively small value, though measurement (and other heuristics like
3083 * the type of ops contained) may justify changing this value.
3084 */
3085#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003086
reedd5fa1a42014-08-09 11:08:05 -07003087void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003088 RETURN_ON_NULL(picture);
3089
reed1c2c4412015-04-30 13:09:24 -07003090 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003091 if (matrix && matrix->isIdentity()) {
3092 matrix = nullptr;
3093 }
3094 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3095 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3096 picture->playback(this);
3097 } else {
3098 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003099 }
3100}
robertphillips9b14f262014-06-04 05:40:44 -07003101
reedd5fa1a42014-08-09 11:08:05 -07003102void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3103 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003104 if (!paint || paint->canComputeFastBounds()) {
3105 SkRect bounds = picture->cullRect();
3106 if (paint) {
3107 paint->computeFastBounds(bounds, &bounds);
3108 }
3109 if (matrix) {
3110 matrix->mapRect(&bounds);
3111 }
3112 if (this->quickReject(bounds)) {
3113 return;
3114 }
3115 }
3116
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003117 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003118 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003119}
3120
vjiaoblack95302da2016-07-21 10:25:54 -07003121#ifdef SK_EXPERIMENTAL_SHADOWING
3122void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3123 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003124 const SkPaint* paint,
3125 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003126 RETURN_ON_NULL(picture);
3127
3128 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3129
vjiaoblacke6f5d562016-08-25 06:30:23 -07003130 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003131}
3132
3133void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3134 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003135 const SkPaint* paint,
3136 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003137 if (!paint || paint->canComputeFastBounds()) {
3138 SkRect bounds = picture->cullRect();
3139 if (paint) {
3140 paint->computeFastBounds(bounds, &bounds);
3141 }
3142 if (matrix) {
3143 matrix->mapRect(&bounds);
3144 }
3145 if (this->quickReject(bounds)) {
3146 return;
3147 }
3148 }
3149
3150 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3151
vjiaoblacke6f5d562016-08-25 06:30:23 -07003152 sk_sp<SkImage> povDepthMap;
3153 sk_sp<SkImage> diffuseMap;
3154
vjiaoblack904527d2016-08-09 09:32:09 -07003155 // povDepthMap
3156 {
3157 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003158 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3159 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003160 sk_sp<SkLights> povLight = builder.finish();
3161
3162 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3163 picture->cullRect().height(),
3164 kBGRA_8888_SkColorType,
3165 kOpaque_SkAlphaType);
3166
3167 // Create a new surface (that matches the backend of canvas)
3168 // to create the povDepthMap
3169 sk_sp<SkSurface> surf(this->makeSurface(info));
3170
3171 // Wrap another SPFCanvas around the surface
3172 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3173 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3174
3175 // set the depth map canvas to have the light as the user's POV
3176 depthMapCanvas->setLights(std::move(povLight));
3177
3178 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003179 povDepthMap = surf->makeImageSnapshot();
3180 }
3181
3182 // diffuseMap
3183 {
3184 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3185 picture->cullRect().height(),
3186 kBGRA_8888_SkColorType,
3187 kOpaque_SkAlphaType);
3188
3189 sk_sp<SkSurface> surf(this->makeSurface(info));
3190 surf->getCanvas()->drawPicture(picture);
3191
3192 diffuseMap = surf->makeImageSnapshot();
3193 }
vjiaoblack904527d2016-08-09 09:32:09 -07003194
3195 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3196 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003197 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3198 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003199
3200 // TODO: pass the depth to the shader in vertices, or uniforms
3201 // so we don't have to render depth and color separately
3202 for (int i = 0; i < fLights->numLights(); ++i) {
3203 // skip over ambient lights; they don't cast shadows
3204 // lights that have shadow maps do not need updating (because lights are immutable)
3205 sk_sp<SkImage> depthMap;
3206 SkISize shMapSize;
3207
3208 if (fLights->light(i).getShadowMap() != nullptr) {
3209 continue;
3210 }
3211
3212 if (fLights->light(i).isRadial()) {
3213 shMapSize.fHeight = 1;
3214 shMapSize.fWidth = (int) picture->cullRect().width();
3215
3216 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3217 kBGRA_8888_SkColorType,
3218 kOpaque_SkAlphaType);
3219
3220 // Create new surface (that matches the backend of canvas)
3221 // for each shadow map
3222 sk_sp<SkSurface> surf(this->makeSurface(info));
3223
3224 // Wrap another SPFCanvas around the surface
3225 SkCanvas* depthMapCanvas = surf->getCanvas();
3226
3227 SkLights::Builder builder;
3228 builder.add(fLights->light(i));
3229 sk_sp<SkLights> curLight = builder.finish();
3230
3231 sk_sp<SkShader> shadowMapShader;
3232 shadowMapShader = SkRadialShadowMapShader::Make(
3233 povDepthShader, curLight,
3234 (int) picture->cullRect().width(),
3235 (int) picture->cullRect().height());
3236
3237 SkPaint shadowMapPaint;
3238 shadowMapPaint.setShader(std::move(shadowMapShader));
3239
3240 depthMapCanvas->setLights(curLight);
3241
3242 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3243 diffuseMap->height()),
3244 shadowMapPaint);
3245
3246 depthMap = surf->makeImageSnapshot();
3247
3248 } else {
3249 // TODO: compute the correct size of the depth map from the light properties
3250 // TODO: maybe add a kDepth_8_SkColorType
3251 // TODO: find actual max depth of picture
3252 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3253 fLights->light(i), 255,
3254 (int) picture->cullRect().width(),
3255 (int) picture->cullRect().height());
3256
3257 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3258 kBGRA_8888_SkColorType,
3259 kOpaque_SkAlphaType);
3260
3261 // Create a new surface (that matches the backend of canvas)
3262 // for each shadow map
3263 sk_sp<SkSurface> surf(this->makeSurface(info));
3264
3265 // Wrap another SPFCanvas around the surface
3266 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3267 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3268 depthMapCanvas->setShadowParams(params);
3269
3270 // set the depth map canvas to have the light we're drawing.
3271 SkLights::Builder builder;
3272 builder.add(fLights->light(i));
3273 sk_sp<SkLights> curLight = builder.finish();
3274 depthMapCanvas->setLights(std::move(curLight));
3275
3276 depthMapCanvas->drawPicture(picture);
3277 depthMap = surf->makeImageSnapshot();
3278 }
3279
3280 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3281 fLights->light(i).setShadowMap(std::move(depthMap));
3282 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3283 // we blur the variance map
3284 SkPaint blurPaint;
3285 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3286 params.fShadowRadius, nullptr));
3287
3288 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3289 kBGRA_8888_SkColorType,
3290 kOpaque_SkAlphaType);
3291
3292 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3293
3294 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3295
3296 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3297 }
3298 }
3299
3300 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003301 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3302 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003303 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003304 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003305 diffuseMap->height(),
3306 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003307
3308 shadowPaint.setShader(shadowShader);
3309
3310 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003311}
3312#endif
3313
reed@android.com8a1c16f2008-12-17 15:59:43 +00003314///////////////////////////////////////////////////////////////////////////////
3315///////////////////////////////////////////////////////////////////////////////
3316
reed3aafe112016-08-18 12:45:34 -07003317SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003318 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003319
3320 SkASSERT(canvas);
3321
reed3aafe112016-08-18 12:45:34 -07003322 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003323 fDone = !fImpl->next();
3324}
3325
3326SkCanvas::LayerIter::~LayerIter() {
3327 fImpl->~SkDrawIter();
3328}
3329
3330void SkCanvas::LayerIter::next() {
3331 fDone = !fImpl->next();
3332}
3333
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003334SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003335 return fImpl->getDevice();
3336}
3337
3338const SkMatrix& SkCanvas::LayerIter::matrix() const {
3339 return fImpl->getMatrix();
3340}
3341
3342const SkPaint& SkCanvas::LayerIter::paint() const {
3343 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003344 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003345 paint = &fDefaultPaint;
3346 }
3347 return *paint;
3348}
3349
reed1e7f5e72016-04-27 07:49:17 -07003350const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003351int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3352int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003353
3354///////////////////////////////////////////////////////////////////////////////
3355
fmalitac3b589a2014-06-05 12:40:07 -07003356SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003357
3358///////////////////////////////////////////////////////////////////////////////
3359
3360static bool supported_for_raster_canvas(const SkImageInfo& info) {
3361 switch (info.alphaType()) {
3362 case kPremul_SkAlphaType:
3363 case kOpaque_SkAlphaType:
3364 break;
3365 default:
3366 return false;
3367 }
3368
3369 switch (info.colorType()) {
3370 case kAlpha_8_SkColorType:
3371 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003372 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003373 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003374 break;
3375 default:
3376 return false;
3377 }
3378
3379 return true;
3380}
3381
Mike Reed5df49342016-11-12 08:06:55 -06003382std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3383 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003384 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003385 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003386 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003387
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003388 SkBitmap bitmap;
3389 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003390 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003391 }
Mike Reed5df49342016-11-12 08:06:55 -06003392 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003393}
reedd5fa1a42014-08-09 11:08:05 -07003394
3395///////////////////////////////////////////////////////////////////////////////
3396
3397SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003398 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003399 : fCanvas(canvas)
3400 , fSaveCount(canvas->getSaveCount())
3401{
bsalomon49f085d2014-09-05 13:34:00 -07003402 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003403 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003404 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003405 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003406 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003407 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003408 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003409 canvas->save();
3410 }
mtklein6cfa73a2014-08-13 13:33:49 -07003411
bsalomon49f085d2014-09-05 13:34:00 -07003412 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003413 canvas->concat(*matrix);
3414 }
3415}
3416
3417SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3418 fCanvas->restoreToCount(fSaveCount);
3419}
reede8f30622016-03-23 18:59:25 -07003420
Florin Malitaee424ac2016-12-01 12:47:59 -05003421///////////////////////////////////////////////////////////////////////////////
3422
3423SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3424 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3425
Florin Malita439ace92016-12-02 12:05:41 -05003426SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3427 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3428
Florin Malitaee424ac2016-12-01 12:47:59 -05003429SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3430 (void)this->INHERITED::getSaveLayerStrategy(rec);
3431 return kNoLayer_SaveLayerStrategy;
3432}
3433
3434///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003435
reed73603f32016-09-20 08:42:38 -07003436static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3437static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3438static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3439static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3440static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3441static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003442
3443///////////////////////////////////////////////////////////////////////////////////////////////////
3444
3445SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3446 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3447 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3448 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3449 SkIPoint origin = dev->getOrigin();
3450 SkMatrix ctm = this->getTotalMatrix();
3451 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3452
3453 SkIRect clip = fMCRec->fRasterClip.getBounds();
3454 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003455 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003456 clip.setEmpty();
3457 }
3458
3459 fAllocator->updateHandle(handle, ctm, clip);
3460 return handle;
3461 }
3462 return nullptr;
3463}
3464
3465static bool install(SkBitmap* bm, const SkImageInfo& info,
3466 const SkRasterHandleAllocator::Rec& rec) {
3467 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3468 rec.fReleaseProc, rec.fReleaseCtx);
3469}
3470
3471SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3472 SkBitmap* bm) {
3473 SkRasterHandleAllocator::Rec rec;
3474 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3475 return nullptr;
3476 }
3477 return rec.fHandle;
3478}
3479
3480std::unique_ptr<SkCanvas>
3481SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3482 const SkImageInfo& info, const Rec* rec) {
3483 if (!alloc || !supported_for_raster_canvas(info)) {
3484 return nullptr;
3485 }
3486
3487 SkBitmap bm;
3488 Handle hndl;
3489
3490 if (rec) {
3491 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3492 } else {
3493 hndl = alloc->allocBitmap(info, &bm);
3494 }
3495 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3496}