blob: 562e0ae60612ec1b60ddee2faf7b7a2b03fdb94d [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Herb Derby73fe7b02017-02-08 15:12:19 -05008#include "SkArenaAlloc.h"
Mike Reed986480a2017-01-13 22:43:16 +00009#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070011#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070013#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060023#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080024#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000025#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050026#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070027#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070028#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070029#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000030#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070031#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000032#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050033#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070035#include "SkShadowPaintFilterCanvas.h"
36#include "SkShadowShader.h"
robertphillips4418dba2016-03-07 12:45:14 -080037#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000038#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070039#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000040#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000041#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080042#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070043#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080046#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000047#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070048#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050051#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050052#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053
reede3b38ce2016-01-08 09:18:44 -080054#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
55
reedc83a2972015-07-16 07:40:45 -070056/*
57 * Return true if the drawing this rect would hit every pixels in the canvas.
58 *
59 * Returns false if
60 * - rect does not contain the canvas' bounds
61 * - paint is not fill
62 * - paint would blur or otherwise change the coverage of the rect
63 */
64bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
65 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070066 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
67 (int)kNone_ShaderOverrideOpacity,
68 "need_matching_enums0");
69 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
70 (int)kOpaque_ShaderOverrideOpacity,
71 "need_matching_enums1");
72 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
73 (int)kNotOpaque_ShaderOverrideOpacity,
74 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070075
76 const SkISize size = this->getBaseLayerSize();
77 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
78 if (!this->getClipStack()->quickContains(bounds)) {
79 return false;
80 }
81
82 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070083 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070084 return false; // conservative
85 }
halcanaryc5769b22016-08-10 07:13:21 -070086
87 SkRect devRect;
88 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
89 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070090 return false;
91 }
92 }
93
94 if (paint) {
95 SkPaint::Style paintStyle = paint->getStyle();
96 if (!(paintStyle == SkPaint::kFill_Style ||
97 paintStyle == SkPaint::kStrokeAndFill_Style)) {
98 return false;
99 }
100 if (paint->getMaskFilter() || paint->getLooper()
101 || paint->getPathEffect() || paint->getImageFilter()) {
102 return false; // conservative
103 }
104 }
105 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
106}
107
108///////////////////////////////////////////////////////////////////////////////////////////////////
109
reedd990e2f2014-12-22 11:58:30 -0800110static bool gIgnoreSaveLayerBounds;
111void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
112 gIgnoreSaveLayerBounds = ignore;
113}
114bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
115 return gIgnoreSaveLayerBounds;
116}
117
reed0acf1b42014-12-22 16:12:38 -0800118static bool gTreatSpriteAsBitmap;
119void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
120 gTreatSpriteAsBitmap = spriteAsBitmap;
121}
122bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
123 return gTreatSpriteAsBitmap;
124}
125
reed@google.comda17f752012-08-16 18:27:05 +0000126// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127//#define SK_TRACE_SAVERESTORE
128
129#ifdef SK_TRACE_SAVERESTORE
130 static int gLayerCounter;
131 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
132 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
133
134 static int gRecCounter;
135 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
136 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
137
138 static int gCanvasCounter;
139 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
140 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
141#else
142 #define inc_layer()
143 #define dec_layer()
144 #define inc_rec()
145 #define dec_rec()
146 #define inc_canvas()
147 #define dec_canvas()
148#endif
149
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000150typedef SkTLazy<SkPaint> SkLazyPaint;
151
reedc83a2972015-07-16 07:40:45 -0700152void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000153 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700154 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
155 ? SkSurface::kDiscard_ContentChangeMode
156 : SkSurface::kRetain_ContentChangeMode);
157 }
158}
159
160void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
161 ShaderOverrideOpacity overrideOpacity) {
162 if (fSurfaceBase) {
163 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
164 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
165 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
166 // and therefore we don't care which mode we're in.
167 //
168 if (fSurfaceBase->outstandingImageSnapshot()) {
169 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
170 mode = SkSurface::kDiscard_ContentChangeMode;
171 }
172 }
173 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000174 }
175}
176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000179/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 The clip/matrix/proc are fields that reflect the top of the save/restore
181 stack. Whenever the canvas changes, it marks a dirty flag, and then before
182 these are used (assuming we're not on a layer) we rebuild these cache
183 values: they reflect the top of the save stack, but translated and clipped
184 by the device's XY offset and bitmap-bounds.
185*/
186struct DeviceCM {
187 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000188 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000189 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000190 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700191 const SkMatrix* fMatrix;
192 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700193 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194
reed96e657d2015-03-10 17:30:07 -0700195 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700196 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700197 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700198 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700199 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700200 {
reed2c9e2002016-07-25 08:05:22 -0700201 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000202 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700203 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000204 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000206 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700207 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700208 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000209 }
reed@google.com4b226022011-01-11 18:32:13 +0000210
mtkleinfeaadee2015-04-08 11:25:48 -0700211 void reset(const SkIRect& bounds) {
212 SkASSERT(!fPaint);
213 SkASSERT(!fNext);
214 SkASSERT(fDevice);
215 fClip.setRect(bounds);
216 }
217
reed@google.com045e62d2011-10-24 12:19:46 +0000218 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700219 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000220 int x = fDevice->getOrigin().x();
221 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 int width = fDevice->width();
223 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000224
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 if ((x | y) == 0) {
226 fMatrix = &totalMatrix;
227 fClip = totalClip;
228 } else {
229 fMatrixStorage = totalMatrix;
230 fMatrixStorage.postTranslate(SkIntToScalar(-x),
231 SkIntToScalar(-y));
232 fMatrix = &fMatrixStorage;
reed@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()) {
Herb Derby73fe7b02017-02-08 15:12:19 -0500512 fLooperContext = looper->makeContext(canvas, &fAlloc);
reed@google.com129ec222012-05-15 13:24:09 +0000513 fIsSimple = false;
514 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700515 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000516 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700517 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000518 }
519 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000520
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700522 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000523 fCanvas->internalRestore();
524 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000525 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000527
reed@google.com4e2b3d32011-04-07 14:18:59 +0000528 const SkPaint& paint() const {
529 SkASSERT(fPaint);
530 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000531 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000532
reed@google.com129ec222012-05-15 13:24:09 +0000533 bool next(SkDrawFilter::Type drawType) {
534 if (fDone) {
535 return false;
536 } else if (fIsSimple) {
537 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000538 return !fPaint->nothingToDraw();
539 } else {
540 return this->doNext(drawType);
541 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000542 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000543
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544private:
Herb Derby73fe7b02017-02-08 15:12:19 -0500545 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
reeddbc3cef2015-04-29 12:18:57 -0700546 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000547 SkCanvas* fCanvas;
548 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000549 SkDrawFilter* fFilter;
550 const SkPaint* fPaint;
551 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700552 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000553 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000554 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000555 SkDrawLooper::Context* fLooperContext;
Herb Derby73fe7b02017-02-08 15:12:19 -0500556 char fStorage[48];
557 SkArenaAlloc fAlloc {fStorage};
reed@google.com129ec222012-05-15 13:24:09 +0000558
559 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000560};
561
reed@google.com129ec222012-05-15 13:24:09 +0000562bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700563 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000564 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700565 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000566
reeddbc3cef2015-04-29 12:18:57 -0700567 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
568 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000569
reed5c476fb2015-04-20 08:04:21 -0700570 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700571 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700572 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000573 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000574
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000575 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000576 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000577 return false;
578 }
579 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000580 if (!fFilter->filter(paint, drawType)) {
581 fDone = true;
582 return false;
583 }
halcanary96fcdcc2015-08-27 07:41:13 -0700584 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000585 // no looper means we only draw once
586 fDone = true;
587 }
588 }
589 fPaint = paint;
590
591 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000592 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000593 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000594 }
595
596 // call this after any possible paint modifiers
597 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700598 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000599 return false;
600 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000601 return true;
602}
603
reed@android.com8a1c16f2008-12-17 15:59:43 +0000604////////// macros to place around the internal draw calls //////////////////
605
reed3aafe112016-08-18 12:45:34 -0700606#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
607 this->predrawNotify(); \
608 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
609 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800610 SkDrawIter iter(this);
611
612
reed@google.com8926b162012-03-23 15:36:36 +0000613#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000614 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700615 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000616 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000617 SkDrawIter iter(this);
618
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000619#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000620 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700621 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000622 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000623 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000624
reedc83a2972015-07-16 07:40:45 -0700625#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
626 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700627 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700628 while (looper.next(type)) { \
629 SkDrawIter iter(this);
630
reed@google.com4e2b3d32011-04-07 14:18:59 +0000631#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000632
633////////////////////////////////////////////////////////////////////////////
634
msarettfbfa2582016-08-12 08:29:08 -0700635static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
636 if (bounds.isEmpty()) {
637 return SkRect::MakeEmpty();
638 }
639
640 // Expand bounds out by 1 in case we are anti-aliasing. We store the
641 // bounds as floats to enable a faster quick reject implementation.
642 SkRect dst;
643 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
644 return dst;
645}
646
mtkleinfeaadee2015-04-08 11:25:48 -0700647void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
648 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700649 fClipStack->reset();
650 fMCRec->reset(bounds);
651
652 // We're peering through a lot of structs here. Only at this scope do we
653 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
654 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700655 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700656 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700657}
658
reedd9544982014-09-09 18:46:22 -0700659SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800660 if (device && device->forceConservativeRasterClip()) {
661 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
662 }
663 // Since init() is only called once by our constructors, it is safe to perform this
664 // const-cast.
665 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
666
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000667 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700668 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800669 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700670 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700671#ifdef SK_EXPERIMENTAL_SHADOWING
672 fLights = nullptr;
673#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674
halcanary385fe4d2015-08-26 13:07:48 -0700675 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700676
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700678 new (fMCRec) MCRec(fConservativeRasterClip);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500679 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700680 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681
reeda499f902015-05-01 09:34:31 -0700682 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
683 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700684 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700685 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700686
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000688
halcanary96fcdcc2015-08-27 07:41:13 -0700689 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000690
reedf92c8662014-08-18 08:02:43 -0700691 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700692 // The root device and the canvas should always have the same pixel geometry
693 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700694 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800695 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700696 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700697 }
msarettfbfa2582016-08-12 08:29:08 -0700698
reedf92c8662014-08-18 08:02:43 -0700699 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000700}
701
reed@google.comcde92112011-07-06 20:00:52 +0000702SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000703 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700704 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800705 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000706{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000707 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000708
halcanary96fcdcc2015-08-27 07:41:13 -0700709 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000710}
711
reedd9544982014-09-09 18:46:22 -0700712static SkBitmap make_nopixels(int width, int height) {
713 SkBitmap bitmap;
714 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
715 return bitmap;
716}
717
718class SkNoPixelsBitmapDevice : public SkBitmapDevice {
719public:
robertphillipsfcf78292015-06-19 11:49:52 -0700720 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
721 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800722 {
723 this->setOrigin(bounds.x(), bounds.y());
724 }
reedd9544982014-09-09 18:46:22 -0700725
726private:
piotaixrb5fae932014-09-24 13:03:30 -0700727
reedd9544982014-09-09 18:46:22 -0700728 typedef SkBitmapDevice INHERITED;
729};
730
reed96a857e2015-01-25 10:33:58 -0800731SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000732 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800733 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800734 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000735{
736 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700737
halcanary385fe4d2015-08-26 13:07:48 -0700738 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
739 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700740}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000741
reed78e27682014-11-19 08:04:34 -0800742SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700743 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700744 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800745 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700746{
747 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700748
halcanary385fe4d2015-08-26 13:07:48 -0700749 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700750}
751
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000752SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000753 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700754 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800755 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000756{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000757 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700758
reedd9544982014-09-09 18:46:22 -0700759 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000760}
761
robertphillipsfcf78292015-06-19 11:49:52 -0700762SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
763 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700764 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800765 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700766{
767 inc_canvas();
768
769 this->init(device, flags);
770}
771
reed4a8126e2014-09-22 07:29:03 -0700772SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700773 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700774 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800775 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700776{
777 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700778
Hal Canary704cd322016-11-07 14:13:52 -0500779 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
780 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700781}
reed29c857d2014-09-21 10:25:07 -0700782
Mike Reed356f7c22017-01-10 11:58:39 -0500783SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
784 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700785 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
786 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500787 , fAllocator(std::move(alloc))
reed42b73eb2015-11-20 13:42:42 -0800788 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700789{
790 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700791
Mike Reed356f7c22017-01-10 11:58:39 -0500792 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500793 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000794}
795
Mike Reed356f7c22017-01-10 11:58:39 -0500796SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
797
reed@android.com8a1c16f2008-12-17 15:59:43 +0000798SkCanvas::~SkCanvas() {
799 // free up the contents of our deque
800 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000801
reed@android.com8a1c16f2008-12-17 15:59:43 +0000802 this->internalRestore(); // restore the last, since we're going away
803
halcanary385fe4d2015-08-26 13:07:48 -0700804 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000805
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806 dec_canvas();
807}
808
fmalita53d9f1c2016-01-25 06:23:54 -0800809#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000810SkDrawFilter* SkCanvas::getDrawFilter() const {
811 return fMCRec->fFilter;
812}
813
814SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700815 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000816 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
817 return filter;
818}
fmalita77650002016-01-21 18:47:11 -0800819#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000820
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000821SkMetaData& SkCanvas::getMetaData() {
822 // metadata users are rare, so we lazily allocate it. If that changes we
823 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700824 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000825 fMetaData = new SkMetaData;
826 }
827 return *fMetaData;
828}
829
reed@android.com8a1c16f2008-12-17 15:59:43 +0000830///////////////////////////////////////////////////////////////////////////////
831
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000832void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700833 this->onFlush();
834}
835
836void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000837 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000838 if (device) {
839 device->flush();
840 }
841}
842
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000843SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000844 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000845 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
846}
847
senorblancoafc7cce2016-02-02 18:44:15 -0800848SkIRect SkCanvas::getTopLayerBounds() const {
849 SkBaseDevice* d = this->getTopDevice();
850 if (!d) {
851 return SkIRect::MakeEmpty();
852 }
853 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
854}
855
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000856SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000857 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000858 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000859 SkASSERT(rec && rec->fLayer);
860 return rec->fLayer->fDevice;
861}
862
Florin Malita0ed3b642017-01-13 16:56:38 +0000863SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000864 return fMCRec->fTopLayer->fDevice;
865}
866
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000867bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000868 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700869 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700870 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000871 return false;
872 }
873 weAllocated = true;
874 }
875
reedcf01e312015-05-23 19:14:51 -0700876 SkAutoPixmapUnlock unlocker;
877 if (bitmap->requestLock(&unlocker)) {
878 const SkPixmap& pm = unlocker.pixmap();
879 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
880 return true;
881 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000882 }
883
884 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500885 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000886 }
887 return false;
888}
reed@google.com51df9e32010-12-23 19:29:18 +0000889
bsalomon@google.comc6980972011-11-02 19:57:21 +0000890bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000891 SkIRect r = srcRect;
892 const SkISize size = this->getBaseLayerSize();
893 if (!r.intersect(0, 0, size.width(), size.height())) {
894 bitmap->reset();
895 return false;
896 }
897
reed84825042014-09-02 12:50:45 -0700898 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000899 // bitmap will already be reset.
900 return false;
901 }
902 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
903 bitmap->reset();
904 return false;
905 }
906 return true;
907}
908
reed96472de2014-12-10 09:53:42 -0800909bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000910 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000911 if (!device) {
912 return false;
913 }
mtkleinf0f14112014-12-12 08:46:25 -0800914
Matt Sarett03dd6d52017-01-23 12:15:09 -0500915 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000916}
917
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000918bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700919 SkAutoPixmapUnlock unlocker;
920 if (bitmap.requestLock(&unlocker)) {
921 const SkPixmap& pm = unlocker.pixmap();
922 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000923 }
924 return false;
925}
926
Matt Sarett03dd6d52017-01-23 12:15:09 -0500927bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000928 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000929 SkBaseDevice* device = this->getDevice();
930 if (!device) {
931 return false;
932 }
933
Matt Sarett03dd6d52017-01-23 12:15:09 -0500934 // This check gives us an early out and prevents generation ID churn on the surface.
935 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
936 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
937 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
938 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000939 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000940
Matt Sarett03dd6d52017-01-23 12:15:09 -0500941 // Tell our owning surface to bump its generation ID.
942 const bool completeOverwrite =
943 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700944 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700945
Matt Sarett03dd6d52017-01-23 12:15:09 -0500946 // This can still fail, most notably in the case of a invalid color type or alpha type
947 // conversion. We could pull those checks into this function and avoid the unnecessary
948 // generation ID bump. But then we would be performing those checks twice, since they
949 // are also necessary at the bitmap/pixmap entry points.
950 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000951}
reed@google.com51df9e32010-12-23 19:29:18 +0000952
reed@android.com8a1c16f2008-12-17 15:59:43 +0000953//////////////////////////////////////////////////////////////////////////////
954
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955void SkCanvas::updateDeviceCMCache() {
956 if (fDeviceCMDirty) {
957 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700958 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000959 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000960
halcanary96fcdcc2015-08-27 07:41:13 -0700961 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700962 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000963 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000964 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965 do {
reedde6c5312016-09-02 12:10:07 -0700966 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700967 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968 }
969 fDeviceCMDirty = false;
970 }
971}
972
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973///////////////////////////////////////////////////////////////////////////////
974
reed2ff1fce2014-12-11 07:07:37 -0800975void SkCanvas::checkForDeferredSave() {
976 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800977 this->doSave();
978 }
979}
980
reedf0090cb2014-11-26 08:55:51 -0800981int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800982#ifdef SK_DEBUG
983 int count = 0;
984 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
985 for (;;) {
986 const MCRec* rec = (const MCRec*)iter.next();
987 if (!rec) {
988 break;
989 }
990 count += 1 + rec->fDeferredSaveCount;
991 }
992 SkASSERT(count == fSaveCount);
993#endif
994 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800995}
996
997int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800998 fSaveCount += 1;
999 fMCRec->fDeferredSaveCount += 1;
1000 return this->getSaveCount() - 1; // return our prev value
1001}
1002
1003void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001004 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001005
1006 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1007 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001008 this->internalSave();
Mike Reed7627fa52017-02-08 10:07:53 -05001009#ifdef SK_USE_DEVICE_CLIPPING
1010 FOR_EACH_TOP_DEVICE(device->save());
1011#endif
reedf0090cb2014-11-26 08:55:51 -08001012}
1013
1014void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001015 if (fMCRec->fDeferredSaveCount > 0) {
1016 SkASSERT(fSaveCount > 1);
1017 fSaveCount -= 1;
1018 fMCRec->fDeferredSaveCount -= 1;
1019 } else {
1020 // check for underflow
1021 if (fMCStack.count() > 1) {
1022 this->willRestore();
1023 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001024 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001025 this->internalRestore();
1026 this->didRestore();
Mike Reed7627fa52017-02-08 10:07:53 -05001027#ifdef SK_USE_DEVICE_CLIPPING
1028 FOR_EACH_TOP_DEVICE(device->restore(fMCRec->fMatrix));
1029#endif
reed2ff1fce2014-12-11 07:07:37 -08001030 }
reedf0090cb2014-11-26 08:55:51 -08001031 }
1032}
1033
1034void SkCanvas::restoreToCount(int count) {
1035 // sanity check
1036 if (count < 1) {
1037 count = 1;
1038 }
mtkleinf0f14112014-12-12 08:46:25 -08001039
reedf0090cb2014-11-26 08:55:51 -08001040 int n = this->getSaveCount() - count;
1041 for (int i = 0; i < n; ++i) {
1042 this->restore();
1043 }
1044}
1045
reed2ff1fce2014-12-11 07:07:37 -08001046void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001047 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001048 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001049 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001050
reed687fa1c2015-04-07 08:00:56 -07001051 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001052}
1053
reed4960eee2015-12-18 07:09:18 -08001054bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001055 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056}
1057
reed4960eee2015-12-18 07:09:18 -08001058bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001059 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -05001060 SkIRect clipBounds = this->getDeviceClipBounds();
1061 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001062 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001063 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001064
reed96e657d2015-03-10 17:30:07 -07001065 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1066
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001067 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001068 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001069 if (bounds && !imageFilter->canComputeFastBounds()) {
1070 bounds = nullptr;
1071 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001072 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001073 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001074 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001075 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001076
reed96e657d2015-03-10 17:30:07 -07001077 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001078 r.roundOut(&ir);
1079 // early exit if the layer's bounds are clipped out
1080 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001081 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001082 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001083 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001084 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001085 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086 }
1087 } else { // no user bounds, so just use the clip
1088 ir = clipBounds;
1089 }
reed180aec42015-03-11 10:39:04 -07001090 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001091
reed4960eee2015-12-18 07:09:18 -08001092 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001093 // Simplify the current clips since they will be applied properly during restore()
Mike Reedc1f77742016-12-09 09:00:50 -05001094 fClipStack->clipDevRect(ir, kReplace_SkClipOp);
reed180aec42015-03-11 10:39:04 -07001095 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001096 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001097 }
1098
1099 if (intersection) {
1100 *intersection = ir;
1101 }
1102 return true;
1103}
1104
reed4960eee2015-12-18 07:09:18 -08001105
reed4960eee2015-12-18 07:09:18 -08001106int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1107 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001108}
1109
reed70ee31b2015-12-10 13:44:45 -08001110int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001111 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1112}
1113
1114int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1115 SaveLayerRec rec(origRec);
1116 if (gIgnoreSaveLayerBounds) {
1117 rec.fBounds = nullptr;
1118 }
1119 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1120 fSaveCount += 1;
1121 this->internalSaveLayer(rec, strategy);
1122 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001123}
1124
reeda2217ef2016-07-20 06:04:34 -07001125void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1126 SkBaseDevice* dst, const SkMatrix& ctm,
1127 const SkClipStack* clipStack) {
1128 SkDraw draw;
1129 SkRasterClip rc;
1130 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1131 if (!dst->accessPixels(&draw.fDst)) {
1132 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001133 }
reeda2217ef2016-07-20 06:04:34 -07001134 draw.fMatrix = &SkMatrix::I();
1135 draw.fRC = &rc;
1136 draw.fClipStack = clipStack;
1137 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001138
1139 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001140 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001141
1142 int x = src->getOrigin().x() - dst->getOrigin().x();
1143 int y = src->getOrigin().y() - dst->getOrigin().y();
1144 auto special = src->snapSpecial();
1145 if (special) {
1146 dst->drawSpecial(draw, special.get(), x, y, p);
1147 }
robertphillips7354a4b2015-12-16 05:08:27 -08001148}
reed70ee31b2015-12-10 13:44:45 -08001149
reed129ed1c2016-02-22 06:42:31 -08001150static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1151 const SkPaint* paint) {
1152 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1153 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001154 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001155 const bool hasImageFilter = paint && paint->getImageFilter();
1156
1157 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1158 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1159 // force to L32
1160 return SkImageInfo::MakeN32(w, h, alphaType);
1161 } else {
1162 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001163 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001164 }
1165}
1166
reed4960eee2015-12-18 07:09:18 -08001167void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1168 const SkRect* bounds = rec.fBounds;
1169 const SkPaint* paint = rec.fPaint;
1170 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1171
reed8c30a812016-04-20 16:36:51 -07001172 SkLazyPaint lazyP;
1173 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1174 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001175 SkMatrix remainder;
1176 SkSize scale;
1177 /*
1178 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1179 * but they do handle scaling. To accommodate this, we do the following:
1180 *
1181 * 1. Stash off the current CTM
1182 * 2. Decompose the CTM into SCALE and REMAINDER
1183 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1184 * contains the REMAINDER
1185 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1186 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1187 * of the original imagefilter, and draw that (via drawSprite)
1188 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1189 *
1190 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1191 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1192 */
reed96a04f32016-04-25 09:25:15 -07001193 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001194 stashedMatrix.decomposeScale(&scale, &remainder))
1195 {
1196 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1197 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1198 SkPaint* p = lazyP.set(*paint);
1199 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1200 SkFilterQuality::kLow_SkFilterQuality,
1201 sk_ref_sp(imageFilter)));
1202 imageFilter = p->getImageFilter();
1203 paint = p;
1204 }
reed8c30a812016-04-20 16:36:51 -07001205
junov@chromium.orga907ac32012-02-24 21:54:07 +00001206 // do this before we create the layer. We don't call the public save() since
1207 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001208 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001209
1210 fDeviceCMDirty = true;
1211
1212 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001213 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001214 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001215 }
1216
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001217 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1218 // the clipRectBounds() call above?
1219 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001220 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001221 }
1222
reed4960eee2015-12-18 07:09:18 -08001223 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001224 SkPixelGeometry geo = fProps.pixelGeometry();
1225 if (paint) {
reed76033be2015-03-14 10:54:31 -07001226 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001227 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001228 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001229 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001230 }
1231 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001232
robertphillips5139e502016-07-19 05:10:40 -07001233 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001234 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001235 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001236 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001237 }
reedb2db8982014-11-13 12:41:02 -08001238
robertphillips5139e502016-07-19 05:10:40 -07001239 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001240 paint);
1241
Hal Canary704cd322016-11-07 14:13:52 -05001242 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001243 {
reed70ee31b2015-12-10 13:44:45 -08001244 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001245 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001246 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001247 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001248 preserveLCDText,
1249 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001250 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1251 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001252 return;
reed61f501f2015-04-29 08:34:00 -07001253 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001254 }
robertphillips5139e502016-07-19 05:10:40 -07001255 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001256
Hal Canary704cd322016-11-07 14:13:52 -05001257 DeviceCM* layer =
1258 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001259
Mike Reedb43a3e02017-02-11 10:18:58 -05001260 // only have a "next" if this new layer doesn't affect the clip (rare)
1261 layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001262 fMCRec->fLayer = layer;
1263 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001264
1265 if (rec.fBackdrop) {
Hal Canary704cd322016-11-07 14:13:52 -05001266 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(),
reeda2217ef2016-07-20 06:04:34 -07001267 fMCRec->fMatrix, this->getClipStack());
1268 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001269}
1270
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001271int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001272 if (0xFF == alpha) {
1273 return this->saveLayer(bounds, nullptr);
1274 } else {
1275 SkPaint tmpPaint;
1276 tmpPaint.setAlpha(alpha);
1277 return this->saveLayer(bounds, &tmpPaint);
1278 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001279}
1280
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281void SkCanvas::internalRestore() {
1282 SkASSERT(fMCStack.count() != 0);
1283
1284 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285
reed687fa1c2015-04-07 08:00:56 -07001286 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001287
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001288 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289 DeviceCM* layer = fMCRec->fLayer; // may be null
1290 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001291 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001292
1293 // now do the normal restore()
1294 fMCRec->~MCRec(); // balanced in save()
1295 fMCStack.pop_back();
1296 fMCRec = (MCRec*)fMCStack.back();
1297
1298 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1299 since if we're being recorded, we don't want to record this (the
1300 recorder will have already recorded the restore).
1301 */
bsalomon49f085d2014-09-05 13:34:00 -07001302 if (layer) {
Mike Reedb43a3e02017-02-11 10:18:58 -05001303 if (fMCRec) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001304 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001305 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001306 // restore what we smashed in internalSaveLayer
1307 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001308 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001310 delete layer;
reedb679ca82015-04-07 04:40:48 -07001311 } else {
1312 // we're at the root
reeda499f902015-05-01 09:34:31 -07001313 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001314 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001315 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001316 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001317 }
msarettfbfa2582016-08-12 08:29:08 -07001318
1319 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001320 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001321 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1322 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323}
1324
reede8f30622016-03-23 18:59:25 -07001325sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001326 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001327 props = &fProps;
1328 }
1329 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001330}
1331
reede8f30622016-03-23 18:59:25 -07001332sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001333 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001334 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001335}
1336
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001337SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001338 return this->onImageInfo();
1339}
1340
1341SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001342 SkBaseDevice* dev = this->getDevice();
1343 if (dev) {
1344 return dev->imageInfo();
1345 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001346 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001347 }
1348}
1349
brianosman898235c2016-04-06 07:38:23 -07001350bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001351 return this->onGetProps(props);
1352}
1353
1354bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001355 SkBaseDevice* dev = this->getDevice();
1356 if (dev) {
1357 if (props) {
1358 *props = fProps;
1359 }
1360 return true;
1361 } else {
1362 return false;
1363 }
1364}
1365
reed6ceeebd2016-03-09 14:26:26 -08001366bool SkCanvas::peekPixels(SkPixmap* pmap) {
1367 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001368}
1369
reed884e97c2015-05-26 11:31:54 -07001370bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001371 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001372 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001373}
1374
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001375void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001376 SkPixmap pmap;
1377 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001378 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001379 }
1380 if (info) {
1381 *info = pmap.info();
1382 }
1383 if (rowBytes) {
1384 *rowBytes = pmap.rowBytes();
1385 }
1386 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001387 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001388 }
reed884e97c2015-05-26 11:31:54 -07001389 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001390}
1391
reed884e97c2015-05-26 11:31:54 -07001392bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001393 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001394 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001395}
1396
reed@android.com8a1c16f2008-12-17 15:59:43 +00001397/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001398
reed7503d602016-07-15 14:23:29 -07001399void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001400 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001401 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001402 paint = &tmp;
1403 }
reed@google.com4b226022011-01-11 18:32:13 +00001404
reed@google.com8926b162012-03-23 15:36:36 +00001405 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001406
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001408 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001409 paint = &looper.paint();
1410 SkImageFilter* filter = paint->getImageFilter();
1411 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001412 if (filter) {
1413 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1414 if (specialImage) {
1415 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1416 }
reed@google.com76dd2772012-01-05 21:15:07 +00001417 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001418 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001419 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420 }
reeda2217ef2016-07-20 06:04:34 -07001421
reed@google.com4e2b3d32011-04-07 14:18:59 +00001422 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423}
1424
reed32704672015-12-16 08:27:10 -08001425/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001426
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001427void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001428 if (dx || dy) {
1429 this->checkForDeferredSave();
1430 fDeviceCMDirty = true;
1431 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001432
reedfe69b502016-09-12 06:31:48 -07001433 // Translate shouldn't affect the is-scale-translateness of the matrix.
1434 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001435
reedfe69b502016-09-12 06:31:48 -07001436 this->didTranslate(dx,dy);
1437 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001438}
1439
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001440void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001441 SkMatrix m;
1442 m.setScale(sx, sy);
1443 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001444}
1445
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001446void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001447 SkMatrix m;
1448 m.setRotate(degrees);
1449 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450}
1451
bungeman7438bfc2016-07-12 15:01:19 -07001452void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1453 SkMatrix m;
1454 m.setRotate(degrees, px, py);
1455 this->concat(m);
1456}
1457
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001458void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001459 SkMatrix m;
1460 m.setSkew(sx, sy);
1461 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001462}
1463
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001464void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001465 if (matrix.isIdentity()) {
1466 return;
1467 }
1468
reed2ff1fce2014-12-11 07:07:37 -08001469 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001470 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001471 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001472 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
Mike Reed7627fa52017-02-08 10:07:53 -05001473
1474#ifdef SK_USE_DEVICE_CLIPPING
1475 FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
1476#endif
1477
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001478 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001479}
1480
reed8c30a812016-04-20 16:36:51 -07001481void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001483 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001484 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001485}
1486
1487void SkCanvas::setMatrix(const SkMatrix& matrix) {
1488 this->checkForDeferredSave();
1489 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001490 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001491}
1492
reed@android.com8a1c16f2008-12-17 15:59:43 +00001493void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001494 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001495}
1496
vjiaoblack95302da2016-07-21 10:25:54 -07001497#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001498void SkCanvas::translateZ(SkScalar z) {
1499 this->checkForDeferredSave();
1500 this->fMCRec->fCurDrawDepth += z;
1501 this->didTranslateZ(z);
1502}
1503
1504SkScalar SkCanvas::getZ() const {
1505 return this->fMCRec->fCurDrawDepth;
1506}
1507
vjiaoblack95302da2016-07-21 10:25:54 -07001508void SkCanvas::setLights(sk_sp<SkLights> lights) {
1509 this->fLights = lights;
1510}
1511
1512sk_sp<SkLights> SkCanvas::getLights() const {
1513 return this->fLights;
1514}
1515#endif
1516
reed@android.com8a1c16f2008-12-17 15:59:43 +00001517//////////////////////////////////////////////////////////////////////////////
1518
Mike Reedc1f77742016-12-09 09:00:50 -05001519void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001520 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001521 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1522 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001523}
1524
Mike Reedc1f77742016-12-09 09:00:50 -05001525void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001526 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001527
1528#ifdef SK_USE_DEVICE_CLIPPING
1529 FOR_EACH_TOP_DEVICE(device->clipRect(rect, op, isAA));
1530#endif
1531
reedc64eff52015-11-21 12:39:45 -08001532 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001533 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1534 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1535 isAA);
reedc64eff52015-11-21 12:39:45 -08001536 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001537 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001538}
1539
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001540void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1541 fClipRestrictionRect = rect;
1542 fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
1543 if (!fClipRestrictionRect.isEmpty()) {
1544 this->checkForDeferredSave();
1545 AutoValidateClip avc(this);
1546 fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
1547 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
1548 fDeviceCMDirty = true;
1549 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1550 }
1551}
1552
Mike Reedc1f77742016-12-09 09:00:50 -05001553void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001554 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001555 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001556 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001557 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1558 } else {
1559 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001560 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001561}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001562
Mike Reedc1f77742016-12-09 09:00:50 -05001563void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001564 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001565
Brian Salomona3b45d42016-10-03 11:36:16 -04001566 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001567
Brian Salomona3b45d42016-10-03 11:36:16 -04001568 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001569
1570#ifdef SK_USE_DEVICE_CLIPPING
1571 FOR_EACH_TOP_DEVICE(device->clipRRect(rrect, op, isAA));
1572#endif
1573
Brian Salomona3b45d42016-10-03 11:36:16 -04001574 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1575 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1576 isAA);
1577 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1578 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001579}
1580
Mike Reedc1f77742016-12-09 09:00:50 -05001581void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001582 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001583 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001584
1585 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1586 SkRect r;
1587 if (path.isRect(&r)) {
1588 this->onClipRect(r, op, edgeStyle);
1589 return;
1590 }
1591 SkRRect rrect;
1592 if (path.isOval(&r)) {
1593 rrect.setOval(r);
1594 this->onClipRRect(rrect, op, edgeStyle);
1595 return;
1596 }
1597 if (path.isRRect(&rrect)) {
1598 this->onClipRRect(rrect, op, edgeStyle);
1599 return;
1600 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001601 }
robertphillips39f05382015-11-24 09:30:12 -08001602
1603 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001604}
1605
Mike Reedc1f77742016-12-09 09:00:50 -05001606void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001607 AutoValidateClip avc(this);
1608
reed@android.com8a1c16f2008-12-17 15:59:43 +00001609 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001610 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
Mike Reed7627fa52017-02-08 10:07:53 -05001611
1612#ifdef SK_USE_DEVICE_CLIPPING
1613 FOR_EACH_TOP_DEVICE(device->clipPath(path, op, isAA));
1614#endif
1615
Brian Salomona3b45d42016-10-03 11:36:16 -04001616 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001617
Brian Salomona3b45d42016-10-03 11:36:16 -04001618 const SkPath* rasterClipPath = &path;
1619 const SkMatrix* matrix = &fMCRec->fMatrix;
1620 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001621 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001622 isAA = getClipStack()->asPath(&tempPath);
1623 rasterClipPath = &tempPath;
1624 matrix = &SkMatrix::I();
Mike Reedc1f77742016-12-09 09:00:50 -05001625 op = kReplace_SkClipOp;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001626 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001627 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1628 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001629 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001630}
1631
Mike Reedc1f77742016-12-09 09:00:50 -05001632void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001633 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001634 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001635}
1636
Mike Reedc1f77742016-12-09 09:00:50 -05001637void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
Mike Reed7627fa52017-02-08 10:07:53 -05001638#ifdef SK_USE_DEVICE_CLIPPING
1639 FOR_EACH_TOP_DEVICE(device->clipRegion(rgn, op));
1640#endif
1641
reed@google.com5c3d1472011-02-22 19:12:23 +00001642 AutoValidateClip avc(this);
1643
reed@android.com8a1c16f2008-12-17 15:59:43 +00001644 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001645
reed@google.com5c3d1472011-02-22 19:12:23 +00001646 // todo: signal fClipStack that we have a region, and therefore (I guess)
1647 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001648 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001649
reed73603f32016-09-20 08:42:38 -07001650 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001651 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001652}
1653
reed@google.com819c9212011-02-23 18:56:55 +00001654#ifdef SK_DEBUG
1655void SkCanvas::validateClip() const {
1656 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001657 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001658 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001659 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001660 return;
1661 }
1662
reed@google.com819c9212011-02-23 18:56:55 +00001663 SkIRect ir;
1664 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001665 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001666
reed687fa1c2015-04-07 08:00:56 -07001667 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001668 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001669 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001670 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001671 case SkClipStack::Element::kRect_Type:
1672 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001673 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001674 break;
1675 case SkClipStack::Element::kEmpty_Type:
1676 tmpClip.setEmpty();
1677 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001678 default: {
1679 SkPath path;
1680 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001681 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1682 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001683 break;
1684 }
reed@google.com819c9212011-02-23 18:56:55 +00001685 }
1686 }
reed@google.com819c9212011-02-23 18:56:55 +00001687}
1688#endif
1689
reed@google.com90c07ea2012-04-13 13:50:27 +00001690void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001691 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001692 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001693
halcanary96fcdcc2015-08-27 07:41:13 -07001694 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001695 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001696 }
1697}
1698
reed@google.com5c3d1472011-02-22 19:12:23 +00001699///////////////////////////////////////////////////////////////////////////////
1700
reed@google.com754de5f2014-02-24 19:38:20 +00001701bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001702 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001703}
1704
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001705bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001706 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001707}
1708
msarettfbfa2582016-08-12 08:29:08 -07001709static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1710#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1711 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1712 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1713 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1714 return 0xF != _mm_movemask_ps(mask);
1715#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1716 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1717 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1718 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1719 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1720#else
1721 SkRect devRectAsRect;
1722 SkRect devClipAsRect;
1723 devRect.store(&devRectAsRect.fLeft);
1724 devClip.store(&devClipAsRect.fLeft);
1725 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1726#endif
1727}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001728
msarettfbfa2582016-08-12 08:29:08 -07001729// It's important for this function to not be inlined. Otherwise the compiler will share code
1730// between the fast path and the slow path, resulting in two slow paths.
1731static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1732 const SkMatrix& matrix) {
1733 SkRect deviceRect;
1734 matrix.mapRect(&deviceRect, src);
1735 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1736}
1737
1738bool SkCanvas::quickReject(const SkRect& src) const {
1739#ifdef SK_DEBUG
1740 // Verify that fDeviceClipBounds are set properly.
1741 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001742 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001743 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001744 } else {
msarettfbfa2582016-08-12 08:29:08 -07001745 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001746 }
msarettfbfa2582016-08-12 08:29:08 -07001747
msarett9637ea92016-08-18 14:03:30 -07001748 // Verify that fIsScaleTranslate is set properly.
1749 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001750#endif
1751
msarett9637ea92016-08-18 14:03:30 -07001752 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001753 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1754 }
1755
1756 // We inline the implementation of mapScaleTranslate() for the fast path.
1757 float sx = fMCRec->fMatrix.getScaleX();
1758 float sy = fMCRec->fMatrix.getScaleY();
1759 float tx = fMCRec->fMatrix.getTranslateX();
1760 float ty = fMCRec->fMatrix.getTranslateY();
1761 Sk4f scale(sx, sy, sx, sy);
1762 Sk4f trans(tx, ty, tx, ty);
1763
1764 // Apply matrix.
1765 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1766
1767 // Make sure left < right, top < bottom.
1768 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1769 Sk4f min = Sk4f::Min(ltrb, rblt);
1770 Sk4f max = Sk4f::Max(ltrb, rblt);
1771 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1772 // ARM this sequence generates the fastest (a single instruction).
1773 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1774
1775 // Check if the device rect is NaN or outside the clip.
1776 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001777}
1778
reed@google.com3b3e8952012-08-16 20:53:31 +00001779bool SkCanvas::quickReject(const SkPath& path) const {
1780 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001781}
1782
Mike Reed42e8c532017-01-23 14:09:13 -05001783SkRect SkCanvas::onGetLocalClipBounds() const {
1784 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001785 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001786 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001787 }
1788
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001789 SkMatrix inverse;
1790 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001791 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001792 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001793 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001794
Mike Reed42e8c532017-01-23 14:09:13 -05001795 SkRect bounds;
1796 SkRect r;
1797 // adjust it outwards in case we are antialiasing
1798 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001799
Mike Reed42e8c532017-01-23 14:09:13 -05001800 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1801 ibounds.fRight + inset, ibounds.fBottom + inset);
1802 inverse.mapRect(&bounds, r);
1803 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001804}
1805
Mike Reed42e8c532017-01-23 14:09:13 -05001806SkIRect SkCanvas::onGetDeviceClipBounds() const {
reed1f836ee2014-07-07 07:49:34 -07001807 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001808 if (clip.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001809 return SkIRect::MakeEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001810 }
Mike Reed42e8c532017-01-23 14:09:13 -05001811 return clip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001812}
1813
reed@android.com8a1c16f2008-12-17 15:59:43 +00001814const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001815 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001816}
1817
Mike Reed3726a4a2017-01-19 11:36:41 -05001818void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1819 // we know that ganesh doesn't track the rgn, so ask for its clipstack
1820 if (this->getGrContext()) {
1821 SkPath path;
1822 this->getClipStack()->asPath(&path);
1823 SkISize size = this->getBaseLayerSize();
1824 rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
1825 } else {
1826 *rgn = fMCRec->fRasterClip.forceGetBW();
1827 }
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001828}
1829
Brian Osman11052242016-10-27 14:47:55 -04001830GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001831 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001832 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001833}
1834
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001835GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001836 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001837 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001838}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001839
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001840void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1841 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001842 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001843 if (outer.isEmpty()) {
1844 return;
1845 }
1846 if (inner.isEmpty()) {
1847 this->drawRRect(outer, paint);
1848 return;
1849 }
1850
1851 // We don't have this method (yet), but technically this is what we should
1852 // be able to assert...
1853 // SkASSERT(outer.contains(inner));
1854 //
1855 // For now at least check for containment of bounds
1856 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1857
1858 this->onDrawDRRect(outer, inner, paint);
1859}
1860
reed41af9662015-01-05 07:49:08 -08001861// These need to stop being virtual -- clients need to override the onDraw... versions
1862
1863void SkCanvas::drawPaint(const SkPaint& paint) {
1864 this->onDrawPaint(paint);
1865}
1866
1867void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1868 this->onDrawRect(r, paint);
1869}
1870
msarettdca352e2016-08-26 06:37:45 -07001871void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1872 if (region.isEmpty()) {
1873 return;
1874 }
1875
1876 if (region.isRect()) {
1877 return this->drawIRect(region.getBounds(), paint);
1878 }
1879
1880 this->onDrawRegion(region, paint);
1881}
1882
reed41af9662015-01-05 07:49:08 -08001883void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1884 this->onDrawOval(r, paint);
1885}
1886
1887void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1888 this->onDrawRRect(rrect, paint);
1889}
1890
1891void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1892 this->onDrawPoints(mode, count, pts, paint);
1893}
1894
1895void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001896 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001897 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001898 this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices,
1899 indexCount, paint);
1900}
1901
1902void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint,
1903 uint32_t flags) {
1904 RETURN_ON_NULL(vertices);
1905 this->onDrawVerticesObject(std::move(vertices), mode, paint, flags);
reed41af9662015-01-05 07:49:08 -08001906}
1907
1908void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1909 this->onDrawPath(path, paint);
1910}
1911
reeda85d4d02015-05-06 12:56:48 -07001912void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001913 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001914 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001915}
1916
reede47829b2015-08-06 10:02:53 -07001917void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1918 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001919 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001920 if (dst.isEmpty() || src.isEmpty()) {
1921 return;
1922 }
1923 this->onDrawImageRect(image, &src, dst, paint, constraint);
1924}
reed41af9662015-01-05 07:49:08 -08001925
reed84984ef2015-07-17 07:09:43 -07001926void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1927 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001928 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001929 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001930}
1931
reede47829b2015-08-06 10:02:53 -07001932void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1933 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001934 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001935 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1936 constraint);
1937}
reede47829b2015-08-06 10:02:53 -07001938
reed4c21dc52015-06-25 12:32:03 -07001939void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1940 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001941 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001942 if (dst.isEmpty()) {
1943 return;
1944 }
msarett552bca92016-08-03 06:53:26 -07001945 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1946 this->onDrawImageNine(image, center, dst, paint);
1947 } else {
reede47829b2015-08-06 10:02:53 -07001948 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001949 }
reed4c21dc52015-06-25 12:32:03 -07001950}
1951
msarett16882062016-08-16 09:31:08 -07001952void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1953 const SkPaint* paint) {
1954 RETURN_ON_NULL(image);
1955 if (dst.isEmpty()) {
1956 return;
1957 }
msarett71df2d72016-09-30 12:41:42 -07001958
1959 SkIRect bounds;
1960 Lattice latticePlusBounds = lattice;
1961 if (!latticePlusBounds.fBounds) {
1962 bounds = SkIRect::MakeWH(image->width(), image->height());
1963 latticePlusBounds.fBounds = &bounds;
1964 }
1965
1966 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1967 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001968 } else {
1969 this->drawImageRect(image, dst, paint);
1970 }
1971}
1972
reed41af9662015-01-05 07:49:08 -08001973void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001974 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001975 return;
1976 }
reed41af9662015-01-05 07:49:08 -08001977 this->onDrawBitmap(bitmap, dx, dy, paint);
1978}
1979
reede47829b2015-08-06 10:02:53 -07001980void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001981 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001982 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001983 return;
1984 }
reede47829b2015-08-06 10:02:53 -07001985 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001986}
1987
reed84984ef2015-07-17 07:09:43 -07001988void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1989 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001990 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001991}
1992
reede47829b2015-08-06 10:02:53 -07001993void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1994 SrcRectConstraint constraint) {
1995 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1996 constraint);
1997}
reede47829b2015-08-06 10:02:53 -07001998
reed41af9662015-01-05 07:49:08 -08001999void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2000 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002001 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002002 return;
2003 }
msarett552bca92016-08-03 06:53:26 -07002004 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2005 this->onDrawBitmapNine(bitmap, center, dst, paint);
2006 } else {
reeda5517e22015-07-14 10:54:12 -07002007 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002008 }
reed41af9662015-01-05 07:49:08 -08002009}
2010
msarettc573a402016-08-02 08:05:56 -07002011void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2012 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002013 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002014 return;
2015 }
msarett71df2d72016-09-30 12:41:42 -07002016
2017 SkIRect bounds;
2018 Lattice latticePlusBounds = lattice;
2019 if (!latticePlusBounds.fBounds) {
2020 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2021 latticePlusBounds.fBounds = &bounds;
2022 }
2023
2024 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2025 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002026 } else {
msarett16882062016-08-16 09:31:08 -07002027 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002028 }
msarettc573a402016-08-02 08:05:56 -07002029}
2030
reed71c3c762015-06-24 10:29:17 -07002031void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002032 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002033 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002034 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002035 if (count <= 0) {
2036 return;
2037 }
Joe Gregorioc4859072017-01-20 14:21:27 +00002038 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002039 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002040 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002041}
2042
reedf70b5312016-03-04 16:36:20 -08002043void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2044 if (key) {
2045 this->onDrawAnnotation(rect, key, value);
2046 }
2047}
2048
reede47829b2015-08-06 10:02:53 -07002049void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2050 const SkPaint* paint, SrcRectConstraint constraint) {
2051 if (src) {
2052 this->drawImageRect(image, *src, dst, paint, constraint);
2053 } else {
2054 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2055 dst, paint, constraint);
2056 }
2057}
2058void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2059 const SkPaint* paint, SrcRectConstraint constraint) {
2060 if (src) {
2061 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2062 } else {
2063 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2064 dst, paint, constraint);
2065 }
2066}
2067
tomhudsoncb3bd182016-05-18 07:24:16 -07002068void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2069 SkIRect layer_bounds = this->getTopLayerBounds();
2070 if (matrix) {
2071 *matrix = this->getTotalMatrix();
2072 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2073 }
2074 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05002075 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07002076 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2077 }
2078}
2079
reed@android.com8a1c16f2008-12-17 15:59:43 +00002080//////////////////////////////////////////////////////////////////////////////
2081// These are the virtual drawing methods
2082//////////////////////////////////////////////////////////////////////////////
2083
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002084void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002085 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002086 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2087 }
2088}
2089
reed41af9662015-01-05 07:49:08 -08002090void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002091 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002092 this->internalDrawPaint(paint);
2093}
2094
2095void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002096 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002097
2098 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002099 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002100 }
2101
reed@google.com4e2b3d32011-04-07 14:18:59 +00002102 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002103}
2104
reed41af9662015-01-05 07:49:08 -08002105void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2106 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002107 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002108 if ((long)count <= 0) {
2109 return;
2110 }
2111
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002112 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002113 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002114 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002115 // special-case 2 points (common for drawing a single line)
2116 if (2 == count) {
2117 r.set(pts[0], pts[1]);
2118 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002119 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002120 }
senorblanco87e066e2015-10-28 11:23:36 -07002121 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2122 return;
2123 }
2124 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002125 }
reed@google.coma584aed2012-05-16 14:06:02 +00002126
halcanary96fcdcc2015-08-27 07:41:13 -07002127 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002128
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002129 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002130
reed@android.com8a1c16f2008-12-17 15:59:43 +00002131 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002132 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002133 }
reed@google.com4b226022011-01-11 18:32:13 +00002134
reed@google.com4e2b3d32011-04-07 14:18:59 +00002135 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002136}
2137
reed4a167172016-08-18 17:15:25 -07002138static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2139 return ((intptr_t)paint.getImageFilter() |
2140#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2141 (intptr_t)canvas->getDrawFilter() |
2142#endif
2143 (intptr_t)paint.getLooper() ) != 0;
2144}
2145
reed41af9662015-01-05 07:49:08 -08002146void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002147 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002148 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002149 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002150 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002151 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2152 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2153 SkRect tmp(r);
2154 tmp.sort();
2155
senorblanco87e066e2015-10-28 11:23:36 -07002156 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2157 return;
2158 }
2159 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002160 }
reed@google.com4b226022011-01-11 18:32:13 +00002161
reed4a167172016-08-18 17:15:25 -07002162 if (needs_autodrawlooper(this, paint)) {
2163 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002164
reed4a167172016-08-18 17:15:25 -07002165 while (iter.next()) {
2166 iter.fDevice->drawRect(iter, r, looper.paint());
2167 }
2168
2169 LOOPER_END
2170 } else {
2171 this->predrawNotify(bounds, &paint, false);
2172 SkDrawIter iter(this);
2173 while (iter.next()) {
2174 iter.fDevice->drawRect(iter, r, paint);
2175 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002176 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002177}
2178
msarett44df6512016-08-25 13:54:30 -07002179void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2180 SkRect storage;
2181 SkRect regionRect = SkRect::Make(region.getBounds());
2182 const SkRect* bounds = nullptr;
2183 if (paint.canComputeFastBounds()) {
2184 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2185 return;
2186 }
2187 bounds = &regionRect;
2188 }
2189
2190 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2191
2192 while (iter.next()) {
2193 iter.fDevice->drawRegion(iter, region, looper.paint());
2194 }
2195
2196 LOOPER_END
2197}
2198
reed41af9662015-01-05 07:49:08 -08002199void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002200 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002201 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002202 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002203 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002204 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2205 return;
2206 }
2207 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002208 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002209
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002210 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002211
2212 while (iter.next()) {
2213 iter.fDevice->drawOval(iter, oval, looper.paint());
2214 }
2215
2216 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002217}
2218
bsalomonac3aa242016-08-19 11:25:19 -07002219void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2220 SkScalar sweepAngle, bool useCenter,
2221 const SkPaint& paint) {
2222 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2223 const SkRect* bounds = nullptr;
2224 if (paint.canComputeFastBounds()) {
2225 SkRect storage;
2226 // Note we're using the entire oval as the bounds.
2227 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2228 return;
2229 }
2230 bounds = &oval;
2231 }
2232
2233 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2234
2235 while (iter.next()) {
2236 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2237 }
2238
2239 LOOPER_END
2240}
2241
reed41af9662015-01-05 07:49:08 -08002242void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002243 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002244 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002245 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002246 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002247 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2248 return;
2249 }
2250 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002251 }
2252
2253 if (rrect.isRect()) {
2254 // call the non-virtual version
2255 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002256 return;
2257 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002258 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002259 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2260 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002261 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002262
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002263 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002264
2265 while (iter.next()) {
2266 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2267 }
2268
2269 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002270}
2271
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002272void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2273 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002274 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002275 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002276 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002277 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2278 return;
2279 }
2280 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002281 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002282
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002283 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002284
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002285 while (iter.next()) {
2286 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2287 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002288
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002289 LOOPER_END
2290}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002291
reed41af9662015-01-05 07:49:08 -08002292void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002293 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002294 if (!path.isFinite()) {
2295 return;
2296 }
2297
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002298 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002299 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002300 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002301 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002302 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2303 return;
2304 }
2305 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002306 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002307
2308 const SkRect& r = path.getBounds();
2309 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002310 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002311 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002312 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002313 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002315
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002316 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002317
2318 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002319 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002320 }
2321
reed@google.com4e2b3d32011-04-07 14:18:59 +00002322 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002323}
2324
reed262a71b2015-12-05 13:07:27 -08002325bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002326 if (!paint.getImageFilter()) {
2327 return false;
2328 }
2329
2330 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002331 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002332 return false;
2333 }
2334
2335 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2336 // Once we can filter and the filter will return a result larger than itself, we should be
2337 // able to remove this constraint.
2338 // skbug.com/4526
2339 //
2340 SkPoint pt;
2341 ctm.mapXY(x, y, &pt);
2342 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2343 return ir.contains(fMCRec->fRasterClip.getBounds());
2344}
2345
reeda85d4d02015-05-06 12:56:48 -07002346void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002347 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002348 SkRect bounds = SkRect::MakeXYWH(x, y,
2349 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002350 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002351 SkRect tmp = bounds;
2352 if (paint) {
2353 paint->computeFastBounds(tmp, &tmp);
2354 }
2355 if (this->quickReject(tmp)) {
2356 return;
2357 }
reeda85d4d02015-05-06 12:56:48 -07002358 }
halcanary9d524f22016-03-29 09:03:52 -07002359
reeda85d4d02015-05-06 12:56:48 -07002360 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002361 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002362 paint = lazy.init();
2363 }
reed262a71b2015-12-05 13:07:27 -08002364
reeda2217ef2016-07-20 06:04:34 -07002365 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002366 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2367 *paint);
2368 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002369 special = this->getDevice()->makeSpecial(image);
2370 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002371 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002372 }
2373 }
2374
reed262a71b2015-12-05 13:07:27 -08002375 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2376
reeda85d4d02015-05-06 12:56:48 -07002377 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002378 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002379 if (special) {
2380 SkPoint pt;
2381 iter.fMatrix->mapXY(x, y, &pt);
2382 iter.fDevice->drawSpecial(iter, special.get(),
2383 SkScalarRoundToInt(pt.fX),
2384 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002385 } else {
2386 iter.fDevice->drawImage(iter, image, x, y, pnt);
2387 }
reeda85d4d02015-05-06 12:56:48 -07002388 }
halcanary9d524f22016-03-29 09:03:52 -07002389
reeda85d4d02015-05-06 12:56:48 -07002390 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002391}
2392
reed41af9662015-01-05 07:49:08 -08002393void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002394 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002395 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002396 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002397 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002398 if (paint) {
2399 paint->computeFastBounds(dst, &storage);
2400 }
2401 if (this->quickReject(storage)) {
2402 return;
2403 }
reeda85d4d02015-05-06 12:56:48 -07002404 }
2405 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002406 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002407 paint = lazy.init();
2408 }
halcanary9d524f22016-03-29 09:03:52 -07002409
senorblancoc41e7e12015-12-07 12:51:30 -08002410 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002411 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002412
reeda85d4d02015-05-06 12:56:48 -07002413 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002414 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002415 }
halcanary9d524f22016-03-29 09:03:52 -07002416
reeda85d4d02015-05-06 12:56:48 -07002417 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002418}
2419
reed41af9662015-01-05 07:49:08 -08002420void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002421 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002422 SkDEBUGCODE(bitmap.validate();)
2423
reed33366972015-10-08 09:22:02 -07002424 if (bitmap.drawsNothing()) {
2425 return;
2426 }
2427
2428 SkLazyPaint lazy;
2429 if (nullptr == paint) {
2430 paint = lazy.init();
2431 }
2432
2433 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2434
2435 SkRect storage;
2436 const SkRect* bounds = nullptr;
2437 if (paint->canComputeFastBounds()) {
2438 bitmap.getBounds(&storage);
2439 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002440 SkRect tmp = storage;
2441 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2442 return;
2443 }
2444 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002445 }
reed@google.com4b226022011-01-11 18:32:13 +00002446
reeda2217ef2016-07-20 06:04:34 -07002447 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002448 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2449 *paint);
2450 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002451 special = this->getDevice()->makeSpecial(bitmap);
2452 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002453 drawAsSprite = false;
2454 }
2455 }
2456
reed262a71b2015-12-05 13:07:27 -08002457 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002458
2459 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002460 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002461 if (special) {
reed262a71b2015-12-05 13:07:27 -08002462 SkPoint pt;
2463 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002464 iter.fDevice->drawSpecial(iter, special.get(),
2465 SkScalarRoundToInt(pt.fX),
2466 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002467 } else {
2468 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2469 }
reed33366972015-10-08 09:22:02 -07002470 }
msarettfbfa2582016-08-12 08:29:08 -07002471
reed33366972015-10-08 09:22:02 -07002472 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473}
2474
reed@google.com9987ec32011-09-07 11:57:52 +00002475// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002476void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002477 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002478 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002479 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002480 return;
2481 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002482
halcanary96fcdcc2015-08-27 07:41:13 -07002483 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002484 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002485 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2486 return;
2487 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488 }
reed@google.com3d608122011-11-21 15:16:16 +00002489
reed@google.com33535f32012-09-25 15:37:50 +00002490 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002491 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002492 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002493 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002494
senorblancoc41e7e12015-12-07 12:51:30 -08002495 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002496 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002497
reed@google.com33535f32012-09-25 15:37:50 +00002498 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002499 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002500 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002501
reed@google.com33535f32012-09-25 15:37:50 +00002502 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002503}
2504
reed41af9662015-01-05 07:49:08 -08002505void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002506 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002507 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002508 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002509 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002510}
2511
reed4c21dc52015-06-25 12:32:03 -07002512void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2513 const SkPaint* paint) {
2514 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002515
halcanary96fcdcc2015-08-27 07:41:13 -07002516 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002517 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002518 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2519 return;
2520 }
reed@google.com3d608122011-11-21 15:16:16 +00002521 }
halcanary9d524f22016-03-29 09:03:52 -07002522
reed4c21dc52015-06-25 12:32:03 -07002523 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002524 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002525 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002526 }
halcanary9d524f22016-03-29 09:03:52 -07002527
senorblancoc41e7e12015-12-07 12:51:30 -08002528 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002529
reed4c21dc52015-06-25 12:32:03 -07002530 while (iter.next()) {
2531 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002532 }
halcanary9d524f22016-03-29 09:03:52 -07002533
reed4c21dc52015-06-25 12:32:03 -07002534 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002535}
2536
reed41af9662015-01-05 07:49:08 -08002537void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2538 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002539 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002540 SkDEBUGCODE(bitmap.validate();)
2541
halcanary96fcdcc2015-08-27 07:41:13 -07002542 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002543 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002544 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2545 return;
2546 }
reed4c21dc52015-06-25 12:32:03 -07002547 }
halcanary9d524f22016-03-29 09:03:52 -07002548
reed4c21dc52015-06-25 12:32:03 -07002549 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002550 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002551 paint = lazy.init();
2552 }
halcanary9d524f22016-03-29 09:03:52 -07002553
senorblancoc41e7e12015-12-07 12:51:30 -08002554 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002555
reed4c21dc52015-06-25 12:32:03 -07002556 while (iter.next()) {
2557 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2558 }
halcanary9d524f22016-03-29 09:03:52 -07002559
reed4c21dc52015-06-25 12:32:03 -07002560 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002561}
2562
msarett16882062016-08-16 09:31:08 -07002563void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2564 const SkPaint* paint) {
2565 if (nullptr == paint || paint->canComputeFastBounds()) {
2566 SkRect storage;
2567 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2568 return;
2569 }
2570 }
2571
2572 SkLazyPaint lazy;
2573 if (nullptr == paint) {
2574 paint = lazy.init();
2575 }
2576
2577 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2578
2579 while (iter.next()) {
2580 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2581 }
2582
2583 LOOPER_END
2584}
2585
2586void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2587 const SkRect& dst, const SkPaint* paint) {
2588 if (nullptr == paint || paint->canComputeFastBounds()) {
2589 SkRect storage;
2590 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2591 return;
2592 }
2593 }
2594
2595 SkLazyPaint lazy;
2596 if (nullptr == paint) {
2597 paint = lazy.init();
2598 }
2599
2600 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2601
2602 while (iter.next()) {
2603 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2604 }
2605
2606 LOOPER_END
2607}
2608
reed@google.comf67e4cf2011-03-15 20:56:58 +00002609class SkDeviceFilteredPaint {
2610public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002611 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002612 uint32_t filteredFlags = device->filterTextFlags(paint);
2613 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002614 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002615 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002616 fPaint = newPaint;
2617 } else {
2618 fPaint = &paint;
2619 }
2620 }
2621
reed@google.comf67e4cf2011-03-15 20:56:58 +00002622 const SkPaint& paint() const { return *fPaint; }
2623
2624private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002625 const SkPaint* fPaint;
2626 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002627};
2628
bungeman@google.com52c748b2011-08-22 21:30:43 +00002629void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2630 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002631 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002632 draw.fDevice->drawRect(draw, r, paint);
2633 } else {
2634 SkPaint p(paint);
Mike Reeda99b6ce2017-02-04 11:04:26 -05002635 p.setStrokeWidth(textSize * paint.getStrokeWidth());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002636 draw.fDevice->drawRect(draw, r, p);
2637 }
2638}
2639
2640void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2641 const char text[], size_t byteLength,
2642 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002643 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002644
2645 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002646 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002647 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002648 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002649 return;
2650 }
2651
2652 SkScalar width = 0;
2653 SkPoint start;
2654
2655 start.set(0, 0); // to avoid warning
2656 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2657 SkPaint::kStrikeThruText_Flag)) {
2658 width = paint.measureText(text, byteLength);
2659
2660 SkScalar offsetX = 0;
2661 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2662 offsetX = SkScalarHalf(width);
2663 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2664 offsetX = width;
2665 }
2666 start.set(x - offsetX, y);
2667 }
2668
2669 if (0 == width) {
2670 return;
2671 }
2672
2673 uint32_t flags = paint.getFlags();
2674
2675 if (flags & (SkPaint::kUnderlineText_Flag |
2676 SkPaint::kStrikeThruText_Flag)) {
2677 SkScalar textSize = paint.getTextSize();
Mike Reeda99b6ce2017-02-04 11:04:26 -05002678 SkScalar height = textSize * kStdUnderline_Thickness;
bungeman@google.com52c748b2011-08-22 21:30:43 +00002679 SkRect r;
2680
2681 r.fLeft = start.fX;
2682 r.fRight = start.fX + width;
2683
2684 if (flags & SkPaint::kUnderlineText_Flag) {
Mike Reeda99b6ce2017-02-04 11:04:26 -05002685 SkScalar offset = textSize * kStdUnderline_Offset + start.fY;
bungeman@google.com52c748b2011-08-22 21:30:43 +00002686 r.fTop = offset;
2687 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002688 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002689 }
2690 if (flags & SkPaint::kStrikeThruText_Flag) {
Mike Reeda99b6ce2017-02-04 11:04:26 -05002691 SkScalar offset = textSize * kStdStrikeThru_Offset + start.fY;
bungeman@google.com52c748b2011-08-22 21:30:43 +00002692 r.fTop = offset;
2693 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002694 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002695 }
2696 }
2697}
2698
reed@google.come0d9ce82014-04-23 04:00:17 +00002699void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2700 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002701 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002702
2703 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002704 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002705 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002706 DrawTextDecorations(iter, dfp.paint(),
2707 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002708 }
2709
reed@google.com4e2b3d32011-04-07 14:18:59 +00002710 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711}
2712
reed@google.come0d9ce82014-04-23 04:00:17 +00002713void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2714 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002715 SkPoint textOffset = SkPoint::Make(0, 0);
2716
halcanary96fcdcc2015-08-27 07:41:13 -07002717 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002718
reed@android.com8a1c16f2008-12-17 15:59:43 +00002719 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002720 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002721 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002722 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002724
reed@google.com4e2b3d32011-04-07 14:18:59 +00002725 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002726}
2727
reed@google.come0d9ce82014-04-23 04:00:17 +00002728void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2729 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002730
2731 SkPoint textOffset = SkPoint::Make(0, constY);
2732
halcanary96fcdcc2015-08-27 07:41:13 -07002733 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002734
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002736 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002737 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002738 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002739 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002740
reed@google.com4e2b3d32011-04-07 14:18:59 +00002741 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002742}
2743
reed@google.come0d9ce82014-04-23 04:00:17 +00002744void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2745 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002746 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002747
reed@android.com8a1c16f2008-12-17 15:59:43 +00002748 while (iter.next()) {
2749 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002750 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002752
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002753 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002754}
2755
reed45561a02016-07-07 12:47:17 -07002756void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2757 const SkRect* cullRect, const SkPaint& paint) {
2758 if (cullRect && this->quickReject(*cullRect)) {
2759 return;
2760 }
2761
2762 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2763
2764 while (iter.next()) {
2765 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2766 }
2767
2768 LOOPER_END
2769}
2770
fmalita00d5c2c2014-08-21 08:53:26 -07002771void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2772 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002773
fmalita85d5eb92015-03-04 11:20:12 -08002774 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002775 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002776 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002777 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002778 SkRect tmp;
2779 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2780 return;
2781 }
2782 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002783 }
2784
fmalita024f9962015-03-03 19:08:17 -08002785 // We cannot filter in the looper as we normally do, because the paint is
2786 // incomplete at this point (text-related attributes are embedded within blob run paints).
2787 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002788 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002789
fmalita85d5eb92015-03-04 11:20:12 -08002790 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002791
fmalitaaa1b9122014-08-28 14:32:24 -07002792 while (iter.next()) {
2793 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002794 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002795 }
2796
fmalitaaa1b9122014-08-28 14:32:24 -07002797 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002798
2799 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002800}
2801
reed@google.come0d9ce82014-04-23 04:00:17 +00002802// These will become non-virtual, so they always call the (virtual) onDraw... method
2803void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2804 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002805 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002806 if (byteLength) {
2807 this->onDrawText(text, byteLength, x, y, paint);
2808 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002809}
2810void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2811 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002812 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002813 if (byteLength) {
2814 this->onDrawPosText(text, byteLength, pos, paint);
2815 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002816}
2817void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2818 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002819 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002820 if (byteLength) {
2821 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2822 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002823}
2824void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2825 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002826 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002827 if (byteLength) {
2828 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2829 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002830}
reed45561a02016-07-07 12:47:17 -07002831void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2832 const SkRect* cullRect, const SkPaint& paint) {
2833 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2834 if (byteLength) {
2835 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2836 }
2837}
fmalita00d5c2c2014-08-21 08:53:26 -07002838void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2839 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002840 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002841 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002842 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002843}
reed@google.come0d9ce82014-04-23 04:00:17 +00002844
reed41af9662015-01-05 07:49:08 -08002845void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2846 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002847 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002848 const uint16_t indices[], int indexCount,
2849 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002850 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002851 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002852
reed@android.com8a1c16f2008-12-17 15:59:43 +00002853 while (iter.next()) {
2854 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002855 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002856 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002857 }
reed@google.com4b226022011-01-11 18:32:13 +00002858
reed@google.com4e2b3d32011-04-07 14:18:59 +00002859 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002860}
2861
Brian Salomon199fb872017-02-06 09:41:10 -05002862void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode,
2863 const SkPaint& paint, uint32_t flags) {
2864 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2865 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2866
2867 while (iter.next()) {
2868 // In the common case of one iteration we could std::move vertices here.
2869 iter.fDevice->drawVerticesObject(iter, vertices, bmode, looper.paint(), flags);
2870 }
2871
2872 LOOPER_END
2873}
2874
2875void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode,
2876 const SkPaint& paint, uint32_t flags) {
2877 const SkPoint* texs =
2878 (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords();
2879 const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors();
2880 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs,
2881 colors, mode, vertices->indices(), vertices->indexCount(), paint);
2882}
2883
dandovb3c9d1c2014-08-12 08:34:29 -07002884void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002885 const SkPoint texCoords[4], SkBlendMode bmode,
2886 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002887 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002888 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002889 return;
2890 }
mtklein6cfa73a2014-08-13 13:33:49 -07002891
Mike Reedfaba3712016-11-03 14:45:31 -04002892 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002893}
2894
2895void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002896 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002897 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002898 // Since a patch is always within the convex hull of the control points, we discard it when its
2899 // bounding rectangle is completely outside the current clip.
2900 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002901 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002902 if (this->quickReject(bounds)) {
2903 return;
2904 }
mtklein6cfa73a2014-08-13 13:33:49 -07002905
halcanary96fcdcc2015-08-27 07:41:13 -07002906 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002907
dandovecfff212014-08-04 10:02:00 -07002908 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002909 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002910 }
mtklein6cfa73a2014-08-13 13:33:49 -07002911
dandovecfff212014-08-04 10:02:00 -07002912 LOOPER_END
2913}
2914
reeda8db7282015-07-07 10:22:31 -07002915void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002916 RETURN_ON_NULL(dr);
2917 if (x || y) {
2918 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2919 this->onDrawDrawable(dr, &matrix);
2920 } else {
2921 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002922 }
2923}
2924
reeda8db7282015-07-07 10:22:31 -07002925void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002926 RETURN_ON_NULL(dr);
2927 if (matrix && matrix->isIdentity()) {
2928 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002929 }
reede3b38ce2016-01-08 09:18:44 -08002930 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002931}
2932
2933void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002934 // drawable bounds are no longer reliable (e.g. android displaylist)
2935 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002936 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002937}
2938
reed71c3c762015-06-24 10:29:17 -07002939void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002940 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002941 const SkRect* cull, const SkPaint* paint) {
2942 if (cull && this->quickReject(*cull)) {
2943 return;
2944 }
2945
2946 SkPaint pnt;
2947 if (paint) {
2948 pnt = *paint;
2949 }
halcanary9d524f22016-03-29 09:03:52 -07002950
halcanary96fcdcc2015-08-27 07:41:13 -07002951 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002952 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002953 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002954 }
2955 LOOPER_END
2956}
2957
reedf70b5312016-03-04 16:36:20 -08002958void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2959 SkASSERT(key);
2960
2961 SkPaint paint;
2962 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2963 while (iter.next()) {
2964 iter.fDevice->drawAnnotation(iter, rect, key, value);
2965 }
2966 LOOPER_END
2967}
2968
reed@android.com8a1c16f2008-12-17 15:59:43 +00002969//////////////////////////////////////////////////////////////////////////////
2970// These methods are NOT virtual, and therefore must call back into virtual
2971// methods, rather than actually drawing themselves.
2972//////////////////////////////////////////////////////////////////////////////
2973
reed374772b2016-10-05 17:33:02 -07002974void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002975 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002976 SkPaint paint;
2977
2978 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002979 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002980 this->drawPaint(paint);
2981}
2982
reed374772b2016-10-05 17:33:02 -07002983void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002984 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002985 SkPaint paint;
2986
2987 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002988 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002989 this->drawPaint(paint);
2990}
2991
2992void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002993 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002994 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002995
reed@android.com8a1c16f2008-12-17 15:59:43 +00002996 pt.set(x, y);
2997 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2998}
2999
3000void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08003001 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003002 SkPoint pt;
3003 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00003004
reed@android.com8a1c16f2008-12-17 15:59:43 +00003005 pt.set(x, y);
3006 paint.setColor(color);
3007 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3008}
3009
3010void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
3011 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003012 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003013 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003014
reed@android.com8a1c16f2008-12-17 15:59:43 +00003015 pts[0].set(x0, y0);
3016 pts[1].set(x1, y1);
3017 this->drawPoints(kLines_PointMode, 2, pts, paint);
3018}
3019
3020void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3021 SkScalar right, SkScalar bottom,
3022 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003023 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003024 SkRect r;
3025
3026 r.set(left, top, right, bottom);
3027 this->drawRect(r, paint);
3028}
3029
3030void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3031 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003032 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003033 if (radius < 0) {
3034 radius = 0;
3035 }
3036
3037 SkRect r;
3038 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003039 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003040}
3041
3042void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3043 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003044 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003045 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003046 SkRRect rrect;
3047 rrect.setRectXY(r, rx, ry);
3048 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003049 } else {
3050 this->drawRect(r, paint);
3051 }
3052}
3053
reed@android.com8a1c16f2008-12-17 15:59:43 +00003054void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3055 SkScalar sweepAngle, bool useCenter,
3056 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003057 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003058 if (oval.isEmpty() || !sweepAngle) {
3059 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003060 }
bsalomon21af9ca2016-08-25 12:29:23 -07003061 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003062}
3063
3064void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3065 const SkPath& path, SkScalar hOffset,
3066 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003067 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003068 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003069
reed@android.com8a1c16f2008-12-17 15:59:43 +00003070 matrix.setTranslate(hOffset, vOffset);
3071 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3072}
3073
reed@android.comf76bacf2009-05-13 14:00:33 +00003074///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003075
3076/**
3077 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3078 * against the playback cost of recursing into the subpicture to get at its actual ops.
3079 *
3080 * For now we pick a conservatively small value, though measurement (and other heuristics like
3081 * the type of ops contained) may justify changing this value.
3082 */
3083#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003084
reedd5fa1a42014-08-09 11:08:05 -07003085void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003086 RETURN_ON_NULL(picture);
3087
reed1c2c4412015-04-30 13:09:24 -07003088 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003089 if (matrix && matrix->isIdentity()) {
3090 matrix = nullptr;
3091 }
3092 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3093 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3094 picture->playback(this);
3095 } else {
3096 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003097 }
3098}
robertphillips9b14f262014-06-04 05:40:44 -07003099
reedd5fa1a42014-08-09 11:08:05 -07003100void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3101 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003102 if (!paint || paint->canComputeFastBounds()) {
3103 SkRect bounds = picture->cullRect();
3104 if (paint) {
3105 paint->computeFastBounds(bounds, &bounds);
3106 }
3107 if (matrix) {
3108 matrix->mapRect(&bounds);
3109 }
3110 if (this->quickReject(bounds)) {
3111 return;
3112 }
3113 }
3114
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003115 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003116 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003117}
3118
vjiaoblack95302da2016-07-21 10:25:54 -07003119#ifdef SK_EXPERIMENTAL_SHADOWING
3120void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3121 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003122 const SkPaint* paint,
3123 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003124 RETURN_ON_NULL(picture);
3125
3126 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3127
vjiaoblacke6f5d562016-08-25 06:30:23 -07003128 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003129}
3130
3131void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3132 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003133 const SkPaint* paint,
3134 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003135 if (!paint || paint->canComputeFastBounds()) {
3136 SkRect bounds = picture->cullRect();
3137 if (paint) {
3138 paint->computeFastBounds(bounds, &bounds);
3139 }
3140 if (matrix) {
3141 matrix->mapRect(&bounds);
3142 }
3143 if (this->quickReject(bounds)) {
3144 return;
3145 }
3146 }
3147
3148 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3149
vjiaoblacke6f5d562016-08-25 06:30:23 -07003150 sk_sp<SkImage> povDepthMap;
3151 sk_sp<SkImage> diffuseMap;
3152
vjiaoblack904527d2016-08-09 09:32:09 -07003153 // povDepthMap
3154 {
3155 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003156 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3157 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003158 sk_sp<SkLights> povLight = builder.finish();
3159
3160 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3161 picture->cullRect().height(),
3162 kBGRA_8888_SkColorType,
3163 kOpaque_SkAlphaType);
3164
3165 // Create a new surface (that matches the backend of canvas)
3166 // to create the povDepthMap
3167 sk_sp<SkSurface> surf(this->makeSurface(info));
3168
3169 // Wrap another SPFCanvas around the surface
3170 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3171 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3172
3173 // set the depth map canvas to have the light as the user's POV
3174 depthMapCanvas->setLights(std::move(povLight));
3175
3176 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003177 povDepthMap = surf->makeImageSnapshot();
3178 }
3179
3180 // diffuseMap
3181 {
3182 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3183 picture->cullRect().height(),
3184 kBGRA_8888_SkColorType,
3185 kOpaque_SkAlphaType);
3186
3187 sk_sp<SkSurface> surf(this->makeSurface(info));
3188 surf->getCanvas()->drawPicture(picture);
3189
3190 diffuseMap = surf->makeImageSnapshot();
3191 }
vjiaoblack904527d2016-08-09 09:32:09 -07003192
3193 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3194 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003195 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3196 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003197
3198 // TODO: pass the depth to the shader in vertices, or uniforms
3199 // so we don't have to render depth and color separately
3200 for (int i = 0; i < fLights->numLights(); ++i) {
3201 // skip over ambient lights; they don't cast shadows
3202 // lights that have shadow maps do not need updating (because lights are immutable)
3203 sk_sp<SkImage> depthMap;
3204 SkISize shMapSize;
3205
3206 if (fLights->light(i).getShadowMap() != nullptr) {
3207 continue;
3208 }
3209
3210 if (fLights->light(i).isRadial()) {
3211 shMapSize.fHeight = 1;
3212 shMapSize.fWidth = (int) picture->cullRect().width();
3213
3214 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3215 kBGRA_8888_SkColorType,
3216 kOpaque_SkAlphaType);
3217
3218 // Create new surface (that matches the backend of canvas)
3219 // for each shadow map
3220 sk_sp<SkSurface> surf(this->makeSurface(info));
3221
3222 // Wrap another SPFCanvas around the surface
3223 SkCanvas* depthMapCanvas = surf->getCanvas();
3224
3225 SkLights::Builder builder;
3226 builder.add(fLights->light(i));
3227 sk_sp<SkLights> curLight = builder.finish();
3228
3229 sk_sp<SkShader> shadowMapShader;
3230 shadowMapShader = SkRadialShadowMapShader::Make(
3231 povDepthShader, curLight,
3232 (int) picture->cullRect().width(),
3233 (int) picture->cullRect().height());
3234
3235 SkPaint shadowMapPaint;
3236 shadowMapPaint.setShader(std::move(shadowMapShader));
3237
3238 depthMapCanvas->setLights(curLight);
3239
3240 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3241 diffuseMap->height()),
3242 shadowMapPaint);
3243
3244 depthMap = surf->makeImageSnapshot();
3245
3246 } else {
3247 // TODO: compute the correct size of the depth map from the light properties
3248 // TODO: maybe add a kDepth_8_SkColorType
3249 // TODO: find actual max depth of picture
3250 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3251 fLights->light(i), 255,
3252 (int) picture->cullRect().width(),
3253 (int) picture->cullRect().height());
3254
3255 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3256 kBGRA_8888_SkColorType,
3257 kOpaque_SkAlphaType);
3258
3259 // Create a new surface (that matches the backend of canvas)
3260 // for each shadow map
3261 sk_sp<SkSurface> surf(this->makeSurface(info));
3262
3263 // Wrap another SPFCanvas around the surface
3264 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3265 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3266 depthMapCanvas->setShadowParams(params);
3267
3268 // set the depth map canvas to have the light we're drawing.
3269 SkLights::Builder builder;
3270 builder.add(fLights->light(i));
3271 sk_sp<SkLights> curLight = builder.finish();
3272 depthMapCanvas->setLights(std::move(curLight));
3273
3274 depthMapCanvas->drawPicture(picture);
3275 depthMap = surf->makeImageSnapshot();
3276 }
3277
3278 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3279 fLights->light(i).setShadowMap(std::move(depthMap));
3280 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3281 // we blur the variance map
3282 SkPaint blurPaint;
3283 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3284 params.fShadowRadius, nullptr));
3285
3286 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3287 kBGRA_8888_SkColorType,
3288 kOpaque_SkAlphaType);
3289
3290 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3291
3292 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3293
3294 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3295 }
3296 }
3297
3298 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003299 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3300 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003301 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003302 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003303 diffuseMap->height(),
3304 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003305
3306 shadowPaint.setShader(shadowShader);
3307
3308 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003309}
3310#endif
3311
reed@android.com8a1c16f2008-12-17 15:59:43 +00003312///////////////////////////////////////////////////////////////////////////////
3313///////////////////////////////////////////////////////////////////////////////
3314
reed3aafe112016-08-18 12:45:34 -07003315SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003316 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003317
3318 SkASSERT(canvas);
3319
reed3aafe112016-08-18 12:45:34 -07003320 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003321 fDone = !fImpl->next();
3322}
3323
3324SkCanvas::LayerIter::~LayerIter() {
3325 fImpl->~SkDrawIter();
3326}
3327
3328void SkCanvas::LayerIter::next() {
3329 fDone = !fImpl->next();
3330}
3331
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003332SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003333 return fImpl->getDevice();
3334}
3335
3336const SkMatrix& SkCanvas::LayerIter::matrix() const {
3337 return fImpl->getMatrix();
3338}
3339
3340const SkPaint& SkCanvas::LayerIter::paint() const {
3341 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003342 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003343 paint = &fDefaultPaint;
3344 }
3345 return *paint;
3346}
3347
reed1e7f5e72016-04-27 07:49:17 -07003348const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003349int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3350int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003351
3352///////////////////////////////////////////////////////////////////////////////
3353
fmalitac3b589a2014-06-05 12:40:07 -07003354SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003355
3356///////////////////////////////////////////////////////////////////////////////
3357
3358static bool supported_for_raster_canvas(const SkImageInfo& info) {
3359 switch (info.alphaType()) {
3360 case kPremul_SkAlphaType:
3361 case kOpaque_SkAlphaType:
3362 break;
3363 default:
3364 return false;
3365 }
3366
3367 switch (info.colorType()) {
3368 case kAlpha_8_SkColorType:
3369 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003370 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003371 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003372 break;
3373 default:
3374 return false;
3375 }
3376
3377 return true;
3378}
3379
Mike Reed5df49342016-11-12 08:06:55 -06003380std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3381 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003382 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003383 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003384 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003385
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003386 SkBitmap bitmap;
3387 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003388 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003389 }
Mike Reed5df49342016-11-12 08:06:55 -06003390 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003391}
reedd5fa1a42014-08-09 11:08:05 -07003392
3393///////////////////////////////////////////////////////////////////////////////
3394
3395SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003396 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003397 : fCanvas(canvas)
3398 , fSaveCount(canvas->getSaveCount())
3399{
bsalomon49f085d2014-09-05 13:34:00 -07003400 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003401 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003402 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003403 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003404 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003405 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003406 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003407 canvas->save();
3408 }
mtklein6cfa73a2014-08-13 13:33:49 -07003409
bsalomon49f085d2014-09-05 13:34:00 -07003410 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003411 canvas->concat(*matrix);
3412 }
3413}
3414
3415SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3416 fCanvas->restoreToCount(fSaveCount);
3417}
reede8f30622016-03-23 18:59:25 -07003418
Florin Malitaee424ac2016-12-01 12:47:59 -05003419///////////////////////////////////////////////////////////////////////////////
3420
3421SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3422 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3423
Florin Malita439ace92016-12-02 12:05:41 -05003424SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3425 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3426
Florin Malitaee424ac2016-12-01 12:47:59 -05003427SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3428 (void)this->INHERITED::getSaveLayerStrategy(rec);
3429 return kNoLayer_SaveLayerStrategy;
3430}
3431
3432///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003433
reed73603f32016-09-20 08:42:38 -07003434static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3435static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3436static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3437static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3438static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3439static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003440
3441///////////////////////////////////////////////////////////////////////////////////////////////////
3442
3443SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3444 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3445 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3446 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3447 SkIPoint origin = dev->getOrigin();
3448 SkMatrix ctm = this->getTotalMatrix();
3449 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3450
3451 SkIRect clip = fMCRec->fRasterClip.getBounds();
3452 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003453 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003454 clip.setEmpty();
3455 }
3456
3457 fAllocator->updateHandle(handle, ctm, clip);
3458 return handle;
3459 }
3460 return nullptr;
3461}
3462
3463static bool install(SkBitmap* bm, const SkImageInfo& info,
3464 const SkRasterHandleAllocator::Rec& rec) {
3465 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3466 rec.fReleaseProc, rec.fReleaseCtx);
3467}
3468
3469SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3470 SkBitmap* bm) {
3471 SkRasterHandleAllocator::Rec rec;
3472 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3473 return nullptr;
3474 }
3475 return rec.fHandle;
3476}
3477
3478std::unique_ptr<SkCanvas>
3479SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3480 const SkImageInfo& info, const Rec* rec) {
3481 if (!alloc || !supported_for_raster_canvas(info)) {
3482 return nullptr;
3483 }
3484
3485 SkBitmap bm;
3486 Handle hndl;
3487
3488 if (rec) {
3489 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3490 } else {
3491 hndl = alloc->allocBitmap(info, &bm);
3492 }
3493 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3494}