blob: eb81bd7951191747096fef9af7f8cd750197af4d [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Mike Reed986480a2017-01-13 22:43:16 +00008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070017#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080018#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070019#include "SkImageFilter.h"
20#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070021#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060022#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050025#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070026#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070027#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070028#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000029#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070030#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000031#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050032#include "SkRasterHandleAllocator.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000033#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070034#include "SkShadowPaintFilterCanvas.h"
35#include "SkShadowShader.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000036#include "SkSmallAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080037#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000038#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070039#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000040#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000041#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080042#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070043#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080046#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000047#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070048#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050051#include "SkClipOpPriv.h"
Brian Salomon199fb872017-02-06 09:41:10 -050052#include "SkVertices.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000053
reede3b38ce2016-01-08 09:18:44 -080054#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
55
reedc83a2972015-07-16 07:40:45 -070056/*
57 * Return true if the drawing this rect would hit every pixels in the canvas.
58 *
59 * Returns false if
60 * - rect does not contain the canvas' bounds
61 * - paint is not fill
62 * - paint would blur or otherwise change the coverage of the rect
63 */
64bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
65 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070066 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
67 (int)kNone_ShaderOverrideOpacity,
68 "need_matching_enums0");
69 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
70 (int)kOpaque_ShaderOverrideOpacity,
71 "need_matching_enums1");
72 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
73 (int)kNotOpaque_ShaderOverrideOpacity,
74 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070075
76 const SkISize size = this->getBaseLayerSize();
77 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
78 if (!this->getClipStack()->quickContains(bounds)) {
79 return false;
80 }
81
82 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070083 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070084 return false; // conservative
85 }
halcanaryc5769b22016-08-10 07:13:21 -070086
87 SkRect devRect;
88 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
89 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070090 return false;
91 }
92 }
93
94 if (paint) {
95 SkPaint::Style paintStyle = paint->getStyle();
96 if (!(paintStyle == SkPaint::kFill_Style ||
97 paintStyle == SkPaint::kStrokeAndFill_Style)) {
98 return false;
99 }
100 if (paint->getMaskFilter() || paint->getLooper()
101 || paint->getPathEffect() || paint->getImageFilter()) {
102 return false; // conservative
103 }
104 }
105 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
106}
107
108///////////////////////////////////////////////////////////////////////////////////////////////////
109
reedd990e2f2014-12-22 11:58:30 -0800110static bool gIgnoreSaveLayerBounds;
111void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
112 gIgnoreSaveLayerBounds = ignore;
113}
114bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
115 return gIgnoreSaveLayerBounds;
116}
117
reed0acf1b42014-12-22 16:12:38 -0800118static bool gTreatSpriteAsBitmap;
119void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
120 gTreatSpriteAsBitmap = spriteAsBitmap;
121}
122bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
123 return gTreatSpriteAsBitmap;
124}
125
reed@google.comda17f752012-08-16 18:27:05 +0000126// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127//#define SK_TRACE_SAVERESTORE
128
129#ifdef SK_TRACE_SAVERESTORE
130 static int gLayerCounter;
131 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
132 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
133
134 static int gRecCounter;
135 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
136 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
137
138 static int gCanvasCounter;
139 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
140 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
141#else
142 #define inc_layer()
143 #define dec_layer()
144 #define inc_rec()
145 #define dec_rec()
146 #define inc_canvas()
147 #define dec_canvas()
148#endif
149
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000150typedef SkTLazy<SkPaint> SkLazyPaint;
151
reedc83a2972015-07-16 07:40:45 -0700152void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000153 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700154 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
155 ? SkSurface::kDiscard_ContentChangeMode
156 : SkSurface::kRetain_ContentChangeMode);
157 }
158}
159
160void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
161 ShaderOverrideOpacity overrideOpacity) {
162 if (fSurfaceBase) {
163 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
164 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
165 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
166 // and therefore we don't care which mode we're in.
167 //
168 if (fSurfaceBase->outstandingImageSnapshot()) {
169 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
170 mode = SkSurface::kDiscard_ContentChangeMode;
171 }
172 }
173 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000174 }
175}
176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000179/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 The clip/matrix/proc are fields that reflect the top of the save/restore
181 stack. Whenever the canvas changes, it marks a dirty flag, and then before
182 these are used (assuming we're not on a layer) we rebuild these cache
183 values: they reflect the top of the save stack, but translated and clipped
184 by the device's XY offset and bitmap-bounds.
185*/
186struct DeviceCM {
187 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000188 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000189 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000190 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700191 const SkMatrix* fMatrix;
192 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700193 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194
reed96e657d2015-03-10 17:30:07 -0700195 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700196 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700197 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700198 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700199 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700200 {
reed2c9e2002016-07-25 08:05:22 -0700201 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000202 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700203 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000204 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000206 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700207 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700208 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000209 }
reed@google.com4b226022011-01-11 18:32:13 +0000210
mtkleinfeaadee2015-04-08 11:25:48 -0700211 void reset(const SkIRect& bounds) {
212 SkASSERT(!fPaint);
213 SkASSERT(!fNext);
214 SkASSERT(fDevice);
215 fClip.setRect(bounds);
216 }
217
reed@google.com045e62d2011-10-24 12:19:46 +0000218 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700219 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000220 int x = fDevice->getOrigin().x();
221 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 int width = fDevice->width();
223 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000224
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 if ((x | y) == 0) {
226 fMatrix = &totalMatrix;
227 fClip = totalClip;
228 } else {
229 fMatrixStorage = totalMatrix;
230 fMatrixStorage.postTranslate(SkIntToScalar(-x),
231 SkIntToScalar(-y));
232 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000233
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 totalClip.translate(-x, -y, &fClip);
235 }
236
reed@google.com045e62d2011-10-24 12:19:46 +0000237 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238
239 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000242 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243 SkRegion::kDifference_Op);
244 }
reed@google.com4b226022011-01-11 18:32:13 +0000245
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246#ifdef SK_DEBUG
247 if (!fClip.isEmpty()) {
248 SkIRect deviceR;
249 deviceR.set(0, 0, width, height);
250 SkASSERT(deviceR.contains(fClip.getBounds()));
251 }
252#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000253 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254};
255
256/* This is the record we keep for each save/restore level in the stack.
257 Since a level optionally copies the matrix and/or stack, we have pointers
258 for these fields. If the value is copied for this level, the copy is
259 stored in the ...Storage field, and the pointer points to that. If the
260 value is not copied for this level, we ignore ...Storage, and just point
261 at the corresponding value in the previous level in the stack.
262*/
263class SkCanvas::MCRec {
264public:
reed1f836ee2014-07-07 07:49:34 -0700265 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700266 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267 /* If there are any layers in the stack, this points to the top-most
268 one that is at or below this level in the stack (so we know what
269 bitmap/device to draw into from this level. This value is NOT
270 reference counted, since the real owner is either our fLayer field,
271 or a previous one in a lower level.)
272 */
reed2ff1fce2014-12-11 07:07:37 -0800273 DeviceCM* fTopLayer;
274 SkRasterClip fRasterClip;
275 SkMatrix fMatrix;
276 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277
vjiaoblacke5de1302016-07-13 14:05:28 -0700278 // This is the current cumulative depth (aggregate of all done translateZ calls)
279 SkScalar fCurDrawDepth;
280
reedd9544982014-09-09 18:46:22 -0700281 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700282 fFilter = nullptr;
283 fLayer = nullptr;
284 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800285 fMatrix.reset();
286 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700287 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700288
reedd9544982014-09-09 18:46:22 -0700289 // don't bother initializing fNext
290 inc_rec();
291 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700292 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
293 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700294 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700295 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700296 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800297 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700298
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299 // don't bother initializing fNext
300 inc_rec();
301 }
302 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000303 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700304 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305 dec_rec();
306 }
mtkleinfeaadee2015-04-08 11:25:48 -0700307
308 void reset(const SkIRect& bounds) {
309 SkASSERT(fLayer);
310 SkASSERT(fDeferredSaveCount == 0);
311
312 fMatrix.reset();
313 fRasterClip.setRect(bounds);
314 fLayer->reset(bounds);
315 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316};
317
reed02f9ed72016-09-06 09:06:18 -0700318static SkIRect compute_device_bounds(SkBaseDevice* device) {
319 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
320 device->width(), device->height());
321}
322
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323class SkDrawIter : public SkDraw {
324public:
reed3aafe112016-08-18 12:45:34 -0700325 SkDrawIter(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000326 canvas->updateDeviceCMCache();
327
bungeman6bd52842016-10-27 09:30:08 -0700328 fClipStack = canvas->getClipStack();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700330
331 fMultiDeviceCS = nullptr;
332 if (fCurrLayer->fNext) {
bungeman6bd52842016-10-27 09:30:08 -0700333 fMultiDeviceCS = canvas->fClipStack.get();
reed02f9ed72016-09-06 09:06:18 -0700334 fMultiDeviceCS->save();
335 }
336 }
337
338 ~SkDrawIter() {
339 if (fMultiDeviceCS) {
340 fMultiDeviceCS->restore();
341 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 }
reed@google.com4b226022011-01-11 18:32:13 +0000343
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700345 if (fMultiDeviceCS && fDevice) {
346 // remove the previous device's bounds
Mike Reedc1f77742016-12-09 09:00:50 -0500347 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), kDifference_SkClipOp);
reed02f9ed72016-09-06 09:06:18 -0700348 }
349
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700351 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
352 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 }
354
reed@google.comf68c5e22012-02-24 16:38:58 +0000355 const DeviceCM* rec = fCurrLayer;
356 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357
358 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000359 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700361 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700362 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700363 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000365 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366
367 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700368 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000369
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 return true;
371 }
372 return false;
373 }
reed@google.com4b226022011-01-11 18:32:13 +0000374
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000375 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700376 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000377 int getX() const { return fDevice->getOrigin().x(); }
378 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000381
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383 const DeviceCM* fCurrLayer;
384 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700385 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000386
387 typedef SkDraw INHERITED;
388};
389
390/////////////////////////////////////////////////////////////////////////////
391
reeddbc3cef2015-04-29 12:18:57 -0700392static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
393 return lazy->isValid() ? lazy->get() : lazy->set(orig);
394}
395
396/**
397 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700398 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700399 */
reedd053ce92016-03-22 10:17:23 -0700400static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700401 SkImageFilter* imgf = paint.getImageFilter();
402 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700403 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700404 }
405
reedd053ce92016-03-22 10:17:23 -0700406 SkColorFilter* imgCFPtr;
407 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700408 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700409 }
reedd053ce92016-03-22 10:17:23 -0700410 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700411
412 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700413 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700414 // there is no existing paint colorfilter, so we can just return the imagefilter's
415 return imgCF;
416 }
417
418 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
419 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700420 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700421}
422
senorblanco87e066e2015-10-28 11:23:36 -0700423/**
424 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
425 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
426 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
427 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
428 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
429 * conservative "effective" bounds based on the settings in the paint... with one exception. This
430 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
431 * deliberately ignored.
432 */
433static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
434 const SkRect& rawBounds,
435 SkRect* storage) {
436 SkPaint tmpUnfiltered(paint);
437 tmpUnfiltered.setImageFilter(nullptr);
438 if (tmpUnfiltered.canComputeFastBounds()) {
439 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
440 } else {
441 return rawBounds;
442 }
443}
444
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445class AutoDrawLooper {
446public:
senorblanco87e066e2015-10-28 11:23:36 -0700447 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
448 // paint. It's used to determine the size of the offscreen layer for filters.
449 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700450 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700451 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000452 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800453#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800455#else
456 fFilter = nullptr;
457#endif
reed4a8126e2014-09-22 07:29:03 -0700458 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000459 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700460 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000461 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000462
reedd053ce92016-03-22 10:17:23 -0700463 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700464 if (simplifiedCF) {
465 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700466 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700467 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700468 fPaint = paint;
469 }
470
471 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700472 /**
473 * We implement ImageFilters for a given draw by creating a layer, then applying the
474 * imagefilter to the pixels of that layer (its backing surface/image), and then
475 * we call restore() to xfer that layer to the main canvas.
476 *
477 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
478 * 2. Generate the src pixels:
479 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
480 * return (fPaint). We then draw the primitive (using srcover) into a cleared
481 * buffer/surface.
482 * 3. Restore the layer created in #1
483 * The imagefilter is passed the buffer/surface from the layer (now filled with the
484 * src pixels of the primitive). It returns a new "filtered" buffer, which we
485 * draw onto the previous layer using the xfermode from the original paint.
486 */
reed@google.com8926b162012-03-23 15:36:36 +0000487 SkPaint tmp;
Mike Reed693fdbd2017-01-12 10:13:40 -0500488 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700489 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700490 SkRect storage;
491 if (rawBounds) {
492 // Make rawBounds include all paint outsets except for those due to image filters.
493 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
494 }
reedbfd5f172016-01-07 11:28:08 -0800495 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700496 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700497 fTempLayerForImageFilter = true;
498 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000499 }
500
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000501 if (SkDrawLooper* looper = paint.getLooper()) {
herbbf6d80a2016-11-15 06:26:56 -0800502 fLooperContext = fLooperContextAllocator.createWithIniter(
503 looper->contextSize(),
504 [&](void* buffer) {
505 return looper->createContext(canvas, buffer);
506 });
reed@google.com129ec222012-05-15 13:24:09 +0000507 fIsSimple = false;
508 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700509 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000510 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700511 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000512 }
513 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000514
reed@android.com8a1c16f2008-12-17 15:59:43 +0000515 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700516 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000517 fCanvas->internalRestore();
518 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000519 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000520 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000521
reed@google.com4e2b3d32011-04-07 14:18:59 +0000522 const SkPaint& paint() const {
523 SkASSERT(fPaint);
524 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000526
reed@google.com129ec222012-05-15 13:24:09 +0000527 bool next(SkDrawFilter::Type drawType) {
528 if (fDone) {
529 return false;
530 } else if (fIsSimple) {
531 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000532 return !fPaint->nothingToDraw();
533 } else {
534 return this->doNext(drawType);
535 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000536 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000537
reed@android.com8a1c16f2008-12-17 15:59:43 +0000538private:
reeddbc3cef2015-04-29 12:18:57 -0700539 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
540 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000541 SkCanvas* fCanvas;
542 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000543 SkDrawFilter* fFilter;
544 const SkPaint* fPaint;
545 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700546 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000547 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000548 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000549 SkDrawLooper::Context* fLooperContext;
550 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000551
552 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553};
554
reed@google.com129ec222012-05-15 13:24:09 +0000555bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700556 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000557 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700558 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000559
reeddbc3cef2015-04-29 12:18:57 -0700560 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
561 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000562
reed5c476fb2015-04-20 08:04:21 -0700563 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700564 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700565 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000566 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000567
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000568 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000569 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000570 return false;
571 }
572 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000573 if (!fFilter->filter(paint, drawType)) {
574 fDone = true;
575 return false;
576 }
halcanary96fcdcc2015-08-27 07:41:13 -0700577 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000578 // no looper means we only draw once
579 fDone = true;
580 }
581 }
582 fPaint = paint;
583
584 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000585 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000586 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000587 }
588
589 // call this after any possible paint modifiers
590 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700591 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000592 return false;
593 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000594 return true;
595}
596
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597////////// macros to place around the internal draw calls //////////////////
598
reed3aafe112016-08-18 12:45:34 -0700599#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
600 this->predrawNotify(); \
601 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
602 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800603 SkDrawIter iter(this);
604
605
reed@google.com8926b162012-03-23 15:36:36 +0000606#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000607 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700608 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000609 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000610 SkDrawIter iter(this);
611
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000612#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000613 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700614 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000615 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000616 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000617
reedc83a2972015-07-16 07:40:45 -0700618#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
619 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700620 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700621 while (looper.next(type)) { \
622 SkDrawIter iter(this);
623
reed@google.com4e2b3d32011-04-07 14:18:59 +0000624#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625
626////////////////////////////////////////////////////////////////////////////
627
msarettfbfa2582016-08-12 08:29:08 -0700628static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
629 if (bounds.isEmpty()) {
630 return SkRect::MakeEmpty();
631 }
632
633 // Expand bounds out by 1 in case we are anti-aliasing. We store the
634 // bounds as floats to enable a faster quick reject implementation.
635 SkRect dst;
636 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
637 return dst;
638}
639
mtkleinfeaadee2015-04-08 11:25:48 -0700640void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
641 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700642 fClipStack->reset();
643 fMCRec->reset(bounds);
644
645 // We're peering through a lot of structs here. Only at this scope do we
646 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
647 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700648 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700649 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700650}
651
reedd9544982014-09-09 18:46:22 -0700652SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800653 if (device && device->forceConservativeRasterClip()) {
654 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
655 }
656 // Since init() is only called once by our constructors, it is safe to perform this
657 // const-cast.
658 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
659
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000660 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700661 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800662 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700663 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700664#ifdef SK_EXPERIMENTAL_SHADOWING
665 fLights = nullptr;
666#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667
halcanary385fe4d2015-08-26 13:07:48 -0700668 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700669
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700671 new (fMCRec) MCRec(fConservativeRasterClip);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500672 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700673 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674
reeda499f902015-05-01 09:34:31 -0700675 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
676 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700677 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700678 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700679
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681
halcanary96fcdcc2015-08-27 07:41:13 -0700682 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000683
reedf92c8662014-08-18 08:02:43 -0700684 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700685 // The root device and the canvas should always have the same pixel geometry
686 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700687 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800688 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700689 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700690 }
msarettfbfa2582016-08-12 08:29:08 -0700691
reedf92c8662014-08-18 08:02:43 -0700692 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693}
694
reed@google.comcde92112011-07-06 20:00:52 +0000695SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000696 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700697 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800698 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000699{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000700 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000701
halcanary96fcdcc2015-08-27 07:41:13 -0700702 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000703}
704
reedd9544982014-09-09 18:46:22 -0700705static SkBitmap make_nopixels(int width, int height) {
706 SkBitmap bitmap;
707 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
708 return bitmap;
709}
710
711class SkNoPixelsBitmapDevice : public SkBitmapDevice {
712public:
robertphillipsfcf78292015-06-19 11:49:52 -0700713 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
714 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800715 {
716 this->setOrigin(bounds.x(), bounds.y());
717 }
reedd9544982014-09-09 18:46:22 -0700718
719private:
piotaixrb5fae932014-09-24 13:03:30 -0700720
reedd9544982014-09-09 18:46:22 -0700721 typedef SkBitmapDevice INHERITED;
722};
723
reed96a857e2015-01-25 10:33:58 -0800724SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000725 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800726 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800727 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000728{
729 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700730
halcanary385fe4d2015-08-26 13:07:48 -0700731 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
732 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700733}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000734
reed78e27682014-11-19 08:04:34 -0800735SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700736 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700737 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800738 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700739{
740 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700741
halcanary385fe4d2015-08-26 13:07:48 -0700742 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700743}
744
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000745SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000746 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700747 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800748 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000749{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700751
reedd9544982014-09-09 18:46:22 -0700752 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753}
754
robertphillipsfcf78292015-06-19 11:49:52 -0700755SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
756 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700757 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800758 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700759{
760 inc_canvas();
761
762 this->init(device, flags);
763}
764
reed4a8126e2014-09-22 07:29:03 -0700765SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700766 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700767 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800768 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700769{
770 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700771
Hal Canary704cd322016-11-07 14:13:52 -0500772 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
773 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700774}
reed29c857d2014-09-21 10:25:07 -0700775
Mike Reed356f7c22017-01-10 11:58:39 -0500776SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
777 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700778 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
779 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500780 , fAllocator(std::move(alloc))
reed42b73eb2015-11-20 13:42:42 -0800781 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700782{
783 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700784
Mike Reed356f7c22017-01-10 11:58:39 -0500785 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500786 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000787}
788
Mike Reed356f7c22017-01-10 11:58:39 -0500789SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
790
reed@android.com8a1c16f2008-12-17 15:59:43 +0000791SkCanvas::~SkCanvas() {
792 // free up the contents of our deque
793 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000794
reed@android.com8a1c16f2008-12-17 15:59:43 +0000795 this->internalRestore(); // restore the last, since we're going away
796
halcanary385fe4d2015-08-26 13:07:48 -0700797 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000798
reed@android.com8a1c16f2008-12-17 15:59:43 +0000799 dec_canvas();
800}
801
fmalita53d9f1c2016-01-25 06:23:54 -0800802#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000803SkDrawFilter* SkCanvas::getDrawFilter() const {
804 return fMCRec->fFilter;
805}
806
807SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700808 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
810 return filter;
811}
fmalita77650002016-01-21 18:47:11 -0800812#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000814SkMetaData& SkCanvas::getMetaData() {
815 // metadata users are rare, so we lazily allocate it. If that changes we
816 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700817 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000818 fMetaData = new SkMetaData;
819 }
820 return *fMetaData;
821}
822
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823///////////////////////////////////////////////////////////////////////////////
824
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000825void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700826 this->onFlush();
827}
828
829void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000830 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000831 if (device) {
832 device->flush();
833 }
834}
835
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000836SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000837 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000838 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
839}
840
senorblancoafc7cce2016-02-02 18:44:15 -0800841SkIRect SkCanvas::getTopLayerBounds() const {
842 SkBaseDevice* d = this->getTopDevice();
843 if (!d) {
844 return SkIRect::MakeEmpty();
845 }
846 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
847}
848
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000849SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000851 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000852 SkASSERT(rec && rec->fLayer);
853 return rec->fLayer->fDevice;
854}
855
Florin Malita0ed3b642017-01-13 16:56:38 +0000856SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000857 return fMCRec->fTopLayer->fDevice;
858}
859
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000860bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000861 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700862 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700863 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000864 return false;
865 }
866 weAllocated = true;
867 }
868
reedcf01e312015-05-23 19:14:51 -0700869 SkAutoPixmapUnlock unlocker;
870 if (bitmap->requestLock(&unlocker)) {
871 const SkPixmap& pm = unlocker.pixmap();
872 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
873 return true;
874 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000875 }
876
877 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500878 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000879 }
880 return false;
881}
reed@google.com51df9e32010-12-23 19:29:18 +0000882
bsalomon@google.comc6980972011-11-02 19:57:21 +0000883bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000884 SkIRect r = srcRect;
885 const SkISize size = this->getBaseLayerSize();
886 if (!r.intersect(0, 0, size.width(), size.height())) {
887 bitmap->reset();
888 return false;
889 }
890
reed84825042014-09-02 12:50:45 -0700891 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000892 // bitmap will already be reset.
893 return false;
894 }
895 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
896 bitmap->reset();
897 return false;
898 }
899 return true;
900}
901
reed96472de2014-12-10 09:53:42 -0800902bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000903 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000904 if (!device) {
905 return false;
906 }
mtkleinf0f14112014-12-12 08:46:25 -0800907
Matt Sarett03dd6d52017-01-23 12:15:09 -0500908 return device->readPixels(dstInfo, dstP, rowBytes, x, y);
reed@google.com51df9e32010-12-23 19:29:18 +0000909}
910
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000911bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700912 SkAutoPixmapUnlock unlocker;
913 if (bitmap.requestLock(&unlocker)) {
914 const SkPixmap& pm = unlocker.pixmap();
915 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000916 }
917 return false;
918}
919
Matt Sarett03dd6d52017-01-23 12:15:09 -0500920bool SkCanvas::writePixels(const SkImageInfo& srcInfo, const void* pixels, size_t rowBytes,
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000921 int x, int y) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000922 SkBaseDevice* device = this->getDevice();
923 if (!device) {
924 return false;
925 }
926
Matt Sarett03dd6d52017-01-23 12:15:09 -0500927 // This check gives us an early out and prevents generation ID churn on the surface.
928 // This is purely optional: it is a subset of the checks performed by SkWritePixelsRec.
929 SkIRect srcRect = SkIRect::MakeXYWH(x, y, srcInfo.width(), srcInfo.height());
930 if (!srcRect.intersect(0, 0, device->width(), device->height())) {
931 return false;
Matt Sarett26ecfe02017-01-23 15:51:01 +0000932 }
Matt Sarett26ecfe02017-01-23 15:51:01 +0000933
Matt Sarett03dd6d52017-01-23 12:15:09 -0500934 // Tell our owning surface to bump its generation ID.
935 const bool completeOverwrite =
936 srcRect.size() == SkISize::Make(device->width(), device->height());
reedc83a2972015-07-16 07:40:45 -0700937 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700938
Matt Sarett03dd6d52017-01-23 12:15:09 -0500939 // This can still fail, most notably in the case of a invalid color type or alpha type
940 // conversion. We could pull those checks into this function and avoid the unnecessary
941 // generation ID bump. But then we would be performing those checks twice, since they
942 // are also necessary at the bitmap/pixmap entry points.
943 return device->writePixels(srcInfo, pixels, rowBytes, x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000944}
reed@google.com51df9e32010-12-23 19:29:18 +0000945
reed@android.com8a1c16f2008-12-17 15:59:43 +0000946//////////////////////////////////////////////////////////////////////////////
947
reed@android.com8a1c16f2008-12-17 15:59:43 +0000948void SkCanvas::updateDeviceCMCache() {
949 if (fDeviceCMDirty) {
950 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700951 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000952 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000953
halcanary96fcdcc2015-08-27 07:41:13 -0700954 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700955 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000956 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000957 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000958 do {
reedde6c5312016-09-02 12:10:07 -0700959 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700960 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000961 }
962 fDeviceCMDirty = false;
963 }
964}
965
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966///////////////////////////////////////////////////////////////////////////////
967
reed2ff1fce2014-12-11 07:07:37 -0800968void SkCanvas::checkForDeferredSave() {
969 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800970 this->doSave();
971 }
972}
973
reedf0090cb2014-11-26 08:55:51 -0800974int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800975#ifdef SK_DEBUG
976 int count = 0;
977 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
978 for (;;) {
979 const MCRec* rec = (const MCRec*)iter.next();
980 if (!rec) {
981 break;
982 }
983 count += 1 + rec->fDeferredSaveCount;
984 }
985 SkASSERT(count == fSaveCount);
986#endif
987 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800988}
989
990int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800991 fSaveCount += 1;
992 fMCRec->fDeferredSaveCount += 1;
993 return this->getSaveCount() - 1; // return our prev value
994}
995
996void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800997 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700998
999 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1000 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001001 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001002}
1003
1004void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001005 if (fMCRec->fDeferredSaveCount > 0) {
1006 SkASSERT(fSaveCount > 1);
1007 fSaveCount -= 1;
1008 fMCRec->fDeferredSaveCount -= 1;
1009 } else {
1010 // check for underflow
1011 if (fMCStack.count() > 1) {
1012 this->willRestore();
1013 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001014 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001015 this->internalRestore();
1016 this->didRestore();
1017 }
reedf0090cb2014-11-26 08:55:51 -08001018 }
1019}
1020
1021void SkCanvas::restoreToCount(int count) {
1022 // sanity check
1023 if (count < 1) {
1024 count = 1;
1025 }
mtkleinf0f14112014-12-12 08:46:25 -08001026
reedf0090cb2014-11-26 08:55:51 -08001027 int n = this->getSaveCount() - count;
1028 for (int i = 0; i < n; ++i) {
1029 this->restore();
1030 }
1031}
1032
reed2ff1fce2014-12-11 07:07:37 -08001033void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001034 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001035 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001036 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001037
reed687fa1c2015-04-07 08:00:56 -07001038 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001039}
1040
reed4960eee2015-12-18 07:09:18 -08001041bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001042 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001043}
1044
reed4960eee2015-12-18 07:09:18 -08001045bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001046 SkIRect* intersection, const SkImageFilter* imageFilter) {
Mike Reed918e1442017-01-23 11:39:45 -05001047 SkIRect clipBounds = this->getDeviceClipBounds();
1048 if (clipBounds.isEmpty()) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001049 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001050 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001051
reed96e657d2015-03-10 17:30:07 -07001052 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1053
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001054 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001055 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001056 if (bounds && !imageFilter->canComputeFastBounds()) {
1057 bounds = nullptr;
1058 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001059 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001060 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001061 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001063
reed96e657d2015-03-10 17:30:07 -07001064 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001065 r.roundOut(&ir);
1066 // early exit if the layer's bounds are clipped out
1067 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001068 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001069 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001070 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001071 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001072 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001073 }
1074 } else { // no user bounds, so just use the clip
1075 ir = clipBounds;
1076 }
reed180aec42015-03-11 10:39:04 -07001077 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001078
reed4960eee2015-12-18 07:09:18 -08001079 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001080 // Simplify the current clips since they will be applied properly during restore()
Mike Reedc1f77742016-12-09 09:00:50 -05001081 fClipStack->clipDevRect(ir, kReplace_SkClipOp);
reed180aec42015-03-11 10:39:04 -07001082 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001083 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001084 }
1085
1086 if (intersection) {
1087 *intersection = ir;
1088 }
1089 return true;
1090}
1091
reed4960eee2015-12-18 07:09:18 -08001092
reed4960eee2015-12-18 07:09:18 -08001093int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1094 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001095}
1096
reed70ee31b2015-12-10 13:44:45 -08001097int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001098 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1099}
1100
1101int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1102 SaveLayerRec rec(origRec);
1103 if (gIgnoreSaveLayerBounds) {
1104 rec.fBounds = nullptr;
1105 }
1106 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1107 fSaveCount += 1;
1108 this->internalSaveLayer(rec, strategy);
1109 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001110}
1111
reeda2217ef2016-07-20 06:04:34 -07001112void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1113 SkBaseDevice* dst, const SkMatrix& ctm,
1114 const SkClipStack* clipStack) {
1115 SkDraw draw;
1116 SkRasterClip rc;
1117 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1118 if (!dst->accessPixels(&draw.fDst)) {
1119 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001120 }
reeda2217ef2016-07-20 06:04:34 -07001121 draw.fMatrix = &SkMatrix::I();
1122 draw.fRC = &rc;
1123 draw.fClipStack = clipStack;
1124 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001125
1126 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001127 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001128
1129 int x = src->getOrigin().x() - dst->getOrigin().x();
1130 int y = src->getOrigin().y() - dst->getOrigin().y();
1131 auto special = src->snapSpecial();
1132 if (special) {
1133 dst->drawSpecial(draw, special.get(), x, y, p);
1134 }
robertphillips7354a4b2015-12-16 05:08:27 -08001135}
reed70ee31b2015-12-10 13:44:45 -08001136
reed129ed1c2016-02-22 06:42:31 -08001137static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1138 const SkPaint* paint) {
1139 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1140 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001141 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001142 const bool hasImageFilter = paint && paint->getImageFilter();
1143
1144 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1145 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1146 // force to L32
1147 return SkImageInfo::MakeN32(w, h, alphaType);
1148 } else {
1149 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001150 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001151 }
1152}
1153
reed4960eee2015-12-18 07:09:18 -08001154void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1155 const SkRect* bounds = rec.fBounds;
1156 const SkPaint* paint = rec.fPaint;
1157 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1158
reed8c30a812016-04-20 16:36:51 -07001159 SkLazyPaint lazyP;
1160 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1161 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001162 SkMatrix remainder;
1163 SkSize scale;
1164 /*
1165 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1166 * but they do handle scaling. To accommodate this, we do the following:
1167 *
1168 * 1. Stash off the current CTM
1169 * 2. Decompose the CTM into SCALE and REMAINDER
1170 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1171 * contains the REMAINDER
1172 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1173 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1174 * of the original imagefilter, and draw that (via drawSprite)
1175 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1176 *
1177 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1178 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1179 */
reed96a04f32016-04-25 09:25:15 -07001180 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001181 stashedMatrix.decomposeScale(&scale, &remainder))
1182 {
1183 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1184 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1185 SkPaint* p = lazyP.set(*paint);
1186 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1187 SkFilterQuality::kLow_SkFilterQuality,
1188 sk_ref_sp(imageFilter)));
1189 imageFilter = p->getImageFilter();
1190 paint = p;
1191 }
reed8c30a812016-04-20 16:36:51 -07001192
junov@chromium.orga907ac32012-02-24 21:54:07 +00001193 // do this before we create the layer. We don't call the public save() since
1194 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001195 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001196
1197 fDeviceCMDirty = true;
1198
1199 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001200 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001201 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001202 }
1203
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001204 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1205 // the clipRectBounds() call above?
1206 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001207 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001208 }
1209
reed4960eee2015-12-18 07:09:18 -08001210 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001211 SkPixelGeometry geo = fProps.pixelGeometry();
1212 if (paint) {
reed76033be2015-03-14 10:54:31 -07001213 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001214 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001215 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001216 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001217 }
1218 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001219
robertphillips5139e502016-07-19 05:10:40 -07001220 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001221 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001222 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001223 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001224 }
reedb2db8982014-11-13 12:41:02 -08001225
robertphillips5139e502016-07-19 05:10:40 -07001226 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001227 paint);
1228
Hal Canary704cd322016-11-07 14:13:52 -05001229 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001230 {
reed70ee31b2015-12-10 13:44:45 -08001231 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001232 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001233 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001234 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001235 preserveLCDText,
1236 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001237 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1238 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001239 return;
reed61f501f2015-04-29 08:34:00 -07001240 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001241 }
robertphillips5139e502016-07-19 05:10:40 -07001242 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001243
Hal Canary704cd322016-11-07 14:13:52 -05001244 DeviceCM* layer =
1245 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246
1247 layer->fNext = fMCRec->fTopLayer;
1248 fMCRec->fLayer = layer;
1249 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001250
1251 if (rec.fBackdrop) {
Hal Canary704cd322016-11-07 14:13:52 -05001252 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(),
reeda2217ef2016-07-20 06:04:34 -07001253 fMCRec->fMatrix, this->getClipStack());
1254 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001255}
1256
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001257int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001258 if (0xFF == alpha) {
1259 return this->saveLayer(bounds, nullptr);
1260 } else {
1261 SkPaint tmpPaint;
1262 tmpPaint.setAlpha(alpha);
1263 return this->saveLayer(bounds, &tmpPaint);
1264 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001265}
1266
reed@android.com8a1c16f2008-12-17 15:59:43 +00001267void SkCanvas::internalRestore() {
1268 SkASSERT(fMCStack.count() != 0);
1269
1270 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271
reed687fa1c2015-04-07 08:00:56 -07001272 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001273
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001274 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275 DeviceCM* layer = fMCRec->fLayer; // may be null
1276 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001277 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278
1279 // now do the normal restore()
1280 fMCRec->~MCRec(); // balanced in save()
1281 fMCStack.pop_back();
1282 fMCRec = (MCRec*)fMCStack.back();
1283
1284 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1285 since if we're being recorded, we don't want to record this (the
1286 recorder will have already recorded the restore).
1287 */
bsalomon49f085d2014-09-05 13:34:00 -07001288 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001290 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001291 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001292 // restore what we smashed in internalSaveLayer
1293 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001294 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001296 delete layer;
reedb679ca82015-04-07 04:40:48 -07001297 } else {
1298 // we're at the root
reeda499f902015-05-01 09:34:31 -07001299 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001300 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001301 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001303 }
msarettfbfa2582016-08-12 08:29:08 -07001304
1305 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001306 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001307 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1308 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309}
1310
reede8f30622016-03-23 18:59:25 -07001311sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001312 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001313 props = &fProps;
1314 }
1315 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001316}
1317
reede8f30622016-03-23 18:59:25 -07001318sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001319 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001320 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001321}
1322
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001323SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001324 return this->onImageInfo();
1325}
1326
1327SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001328 SkBaseDevice* dev = this->getDevice();
1329 if (dev) {
1330 return dev->imageInfo();
1331 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001332 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001333 }
1334}
1335
brianosman898235c2016-04-06 07:38:23 -07001336bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001337 return this->onGetProps(props);
1338}
1339
1340bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001341 SkBaseDevice* dev = this->getDevice();
1342 if (dev) {
1343 if (props) {
1344 *props = fProps;
1345 }
1346 return true;
1347 } else {
1348 return false;
1349 }
1350}
1351
reed6ceeebd2016-03-09 14:26:26 -08001352bool SkCanvas::peekPixels(SkPixmap* pmap) {
1353 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001354}
1355
reed884e97c2015-05-26 11:31:54 -07001356bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001357 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001358 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001359}
1360
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001361void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001362 SkPixmap pmap;
1363 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001364 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001365 }
1366 if (info) {
1367 *info = pmap.info();
1368 }
1369 if (rowBytes) {
1370 *rowBytes = pmap.rowBytes();
1371 }
1372 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001373 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001374 }
reed884e97c2015-05-26 11:31:54 -07001375 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001376}
1377
reed884e97c2015-05-26 11:31:54 -07001378bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001379 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001380 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001381}
1382
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001384
reed7503d602016-07-15 14:23:29 -07001385void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001386 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001387 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001388 paint = &tmp;
1389 }
reed@google.com4b226022011-01-11 18:32:13 +00001390
reed@google.com8926b162012-03-23 15:36:36 +00001391 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001392
reed@android.com8a1c16f2008-12-17 15:59:43 +00001393 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001394 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001395 paint = &looper.paint();
1396 SkImageFilter* filter = paint->getImageFilter();
1397 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001398 if (filter) {
1399 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1400 if (specialImage) {
1401 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1402 }
reed@google.com76dd2772012-01-05 21:15:07 +00001403 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001404 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001405 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001406 }
reeda2217ef2016-07-20 06:04:34 -07001407
reed@google.com4e2b3d32011-04-07 14:18:59 +00001408 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409}
1410
reed32704672015-12-16 08:27:10 -08001411/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001412
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001413void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001414 if (dx || dy) {
1415 this->checkForDeferredSave();
1416 fDeviceCMDirty = true;
1417 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001418
reedfe69b502016-09-12 06:31:48 -07001419 // Translate shouldn't affect the is-scale-translateness of the matrix.
1420 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001421
reedfe69b502016-09-12 06:31:48 -07001422 this->didTranslate(dx,dy);
1423 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424}
1425
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001426void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001427 SkMatrix m;
1428 m.setScale(sx, sy);
1429 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001430}
1431
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001432void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001433 SkMatrix m;
1434 m.setRotate(degrees);
1435 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436}
1437
bungeman7438bfc2016-07-12 15:01:19 -07001438void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1439 SkMatrix m;
1440 m.setRotate(degrees, px, py);
1441 this->concat(m);
1442}
1443
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001444void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001445 SkMatrix m;
1446 m.setSkew(sx, sy);
1447 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001448}
1449
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001450void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001451 if (matrix.isIdentity()) {
1452 return;
1453 }
1454
reed2ff1fce2014-12-11 07:07:37 -08001455 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001456 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001457 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001458 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001459 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001460}
1461
reed8c30a812016-04-20 16:36:51 -07001462void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001463 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001464 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001465 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001466}
1467
1468void SkCanvas::setMatrix(const SkMatrix& matrix) {
1469 this->checkForDeferredSave();
1470 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001471 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001472}
1473
reed@android.com8a1c16f2008-12-17 15:59:43 +00001474void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001475 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476}
1477
vjiaoblack95302da2016-07-21 10:25:54 -07001478#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001479void SkCanvas::translateZ(SkScalar z) {
1480 this->checkForDeferredSave();
1481 this->fMCRec->fCurDrawDepth += z;
1482 this->didTranslateZ(z);
1483}
1484
1485SkScalar SkCanvas::getZ() const {
1486 return this->fMCRec->fCurDrawDepth;
1487}
1488
vjiaoblack95302da2016-07-21 10:25:54 -07001489void SkCanvas::setLights(sk_sp<SkLights> lights) {
1490 this->fLights = lights;
1491}
1492
1493sk_sp<SkLights> SkCanvas::getLights() const {
1494 return this->fLights;
1495}
1496#endif
1497
reed@android.com8a1c16f2008-12-17 15:59:43 +00001498//////////////////////////////////////////////////////////////////////////////
1499
Mike Reedc1f77742016-12-09 09:00:50 -05001500void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001501 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001502 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1503 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001504}
1505
Mike Reedc1f77742016-12-09 09:00:50 -05001506void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001507 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reedc64eff52015-11-21 12:39:45 -08001508 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001509 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1510 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1511 isAA);
reedc64eff52015-11-21 12:39:45 -08001512 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001513 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001514}
1515
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001516void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1517 fClipRestrictionRect = rect;
1518 fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
1519 if (!fClipRestrictionRect.isEmpty()) {
1520 this->checkForDeferredSave();
1521 AutoValidateClip avc(this);
1522 fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
1523 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
1524 fDeviceCMDirty = true;
1525 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1526 }
1527}
1528
Mike Reedc1f77742016-12-09 09:00:50 -05001529void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001530 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001531 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001532 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001533 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1534 } else {
1535 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001536 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001537}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001538
Mike Reedc1f77742016-12-09 09:00:50 -05001539void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001540 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001541
Brian Salomona3b45d42016-10-03 11:36:16 -04001542 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001543
Brian Salomona3b45d42016-10-03 11:36:16 -04001544 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1545 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1546 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1547 isAA);
1548 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1549 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001550}
1551
Mike Reedc1f77742016-12-09 09:00:50 -05001552void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001553 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001554 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001555
1556 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1557 SkRect r;
1558 if (path.isRect(&r)) {
1559 this->onClipRect(r, op, edgeStyle);
1560 return;
1561 }
1562 SkRRect rrect;
1563 if (path.isOval(&r)) {
1564 rrect.setOval(r);
1565 this->onClipRRect(rrect, op, edgeStyle);
1566 return;
1567 }
1568 if (path.isRRect(&rrect)) {
1569 this->onClipRRect(rrect, op, edgeStyle);
1570 return;
1571 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001572 }
robertphillips39f05382015-11-24 09:30:12 -08001573
1574 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001575}
1576
Mike Reedc1f77742016-12-09 09:00:50 -05001577void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001578 AutoValidateClip avc(this);
1579
reed@android.com8a1c16f2008-12-17 15:59:43 +00001580 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001581 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001582
Brian Salomona3b45d42016-10-03 11:36:16 -04001583 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001584
Brian Salomona3b45d42016-10-03 11:36:16 -04001585 const SkPath* rasterClipPath = &path;
1586 const SkMatrix* matrix = &fMCRec->fMatrix;
1587 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001588 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001589 isAA = getClipStack()->asPath(&tempPath);
1590 rasterClipPath = &tempPath;
1591 matrix = &SkMatrix::I();
Mike Reedc1f77742016-12-09 09:00:50 -05001592 op = kReplace_SkClipOp;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001593 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001594 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1595 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001596 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001597}
1598
Mike Reedc1f77742016-12-09 09:00:50 -05001599void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001600 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001601 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001602}
1603
Mike Reedc1f77742016-12-09 09:00:50 -05001604void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001605 AutoValidateClip avc(this);
1606
reed@android.com8a1c16f2008-12-17 15:59:43 +00001607 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001608
reed@google.com5c3d1472011-02-22 19:12:23 +00001609 // todo: signal fClipStack that we have a region, and therefore (I guess)
1610 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001611 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001612
reed73603f32016-09-20 08:42:38 -07001613 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001614 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001615}
1616
reed@google.com819c9212011-02-23 18:56:55 +00001617#ifdef SK_DEBUG
1618void SkCanvas::validateClip() const {
1619 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001620 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001621 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001622 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001623 return;
1624 }
1625
reed@google.com819c9212011-02-23 18:56:55 +00001626 SkIRect ir;
1627 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001628 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001629
reed687fa1c2015-04-07 08:00:56 -07001630 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001631 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001632 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001633 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001634 case SkClipStack::Element::kRect_Type:
1635 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001636 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001637 break;
1638 case SkClipStack::Element::kEmpty_Type:
1639 tmpClip.setEmpty();
1640 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001641 default: {
1642 SkPath path;
1643 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001644 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1645 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001646 break;
1647 }
reed@google.com819c9212011-02-23 18:56:55 +00001648 }
1649 }
reed@google.com819c9212011-02-23 18:56:55 +00001650}
1651#endif
1652
reed@google.com90c07ea2012-04-13 13:50:27 +00001653void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001654 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001655 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001656
halcanary96fcdcc2015-08-27 07:41:13 -07001657 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001658 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001659 }
1660}
1661
reed@google.com5c3d1472011-02-22 19:12:23 +00001662///////////////////////////////////////////////////////////////////////////////
1663
reed@google.com754de5f2014-02-24 19:38:20 +00001664bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001665 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001666}
1667
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001668bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001669 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001670}
1671
msarettfbfa2582016-08-12 08:29:08 -07001672static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1673#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1674 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1675 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1676 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1677 return 0xF != _mm_movemask_ps(mask);
1678#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1679 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1680 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1681 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1682 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1683#else
1684 SkRect devRectAsRect;
1685 SkRect devClipAsRect;
1686 devRect.store(&devRectAsRect.fLeft);
1687 devClip.store(&devClipAsRect.fLeft);
1688 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1689#endif
1690}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001691
msarettfbfa2582016-08-12 08:29:08 -07001692// It's important for this function to not be inlined. Otherwise the compiler will share code
1693// between the fast path and the slow path, resulting in two slow paths.
1694static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1695 const SkMatrix& matrix) {
1696 SkRect deviceRect;
1697 matrix.mapRect(&deviceRect, src);
1698 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1699}
1700
1701bool SkCanvas::quickReject(const SkRect& src) const {
1702#ifdef SK_DEBUG
1703 // Verify that fDeviceClipBounds are set properly.
1704 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001705 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001706 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001707 } else {
msarettfbfa2582016-08-12 08:29:08 -07001708 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001709 }
msarettfbfa2582016-08-12 08:29:08 -07001710
msarett9637ea92016-08-18 14:03:30 -07001711 // Verify that fIsScaleTranslate is set properly.
1712 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001713#endif
1714
msarett9637ea92016-08-18 14:03:30 -07001715 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001716 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1717 }
1718
1719 // We inline the implementation of mapScaleTranslate() for the fast path.
1720 float sx = fMCRec->fMatrix.getScaleX();
1721 float sy = fMCRec->fMatrix.getScaleY();
1722 float tx = fMCRec->fMatrix.getTranslateX();
1723 float ty = fMCRec->fMatrix.getTranslateY();
1724 Sk4f scale(sx, sy, sx, sy);
1725 Sk4f trans(tx, ty, tx, ty);
1726
1727 // Apply matrix.
1728 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1729
1730 // Make sure left < right, top < bottom.
1731 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1732 Sk4f min = Sk4f::Min(ltrb, rblt);
1733 Sk4f max = Sk4f::Max(ltrb, rblt);
1734 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1735 // ARM this sequence generates the fastest (a single instruction).
1736 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1737
1738 // Check if the device rect is NaN or outside the clip.
1739 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001740}
1741
reed@google.com3b3e8952012-08-16 20:53:31 +00001742bool SkCanvas::quickReject(const SkPath& path) const {
1743 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001744}
1745
Mike Reed42e8c532017-01-23 14:09:13 -05001746SkRect SkCanvas::onGetLocalClipBounds() const {
1747 SkIRect ibounds = this->onGetDeviceClipBounds();
Mike Reed918e1442017-01-23 11:39:45 -05001748 if (ibounds.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001749 return SkRect::MakeEmpty();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001750 }
1751
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001752 SkMatrix inverse;
1753 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001754 if (!fMCRec->fMatrix.invert(&inverse)) {
Mike Reed42e8c532017-01-23 14:09:13 -05001755 return SkRect::MakeEmpty();
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001756 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001757
Mike Reed42e8c532017-01-23 14:09:13 -05001758 SkRect bounds;
1759 SkRect r;
1760 // adjust it outwards in case we are antialiasing
1761 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001762
Mike Reed42e8c532017-01-23 14:09:13 -05001763 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1764 ibounds.fRight + inset, ibounds.fBottom + inset);
1765 inverse.mapRect(&bounds, r);
1766 return bounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001767}
1768
Mike Reed42e8c532017-01-23 14:09:13 -05001769SkIRect SkCanvas::onGetDeviceClipBounds() const {
reed1f836ee2014-07-07 07:49:34 -07001770 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001771 if (clip.isEmpty()) {
Mike Reed42e8c532017-01-23 14:09:13 -05001772 return SkIRect::MakeEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001773 }
Mike Reed42e8c532017-01-23 14:09:13 -05001774 return clip.getBounds();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001775}
1776
reed@android.com8a1c16f2008-12-17 15:59:43 +00001777const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001778 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001779}
1780
Mike Reed3726a4a2017-01-19 11:36:41 -05001781void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1782 // we know that ganesh doesn't track the rgn, so ask for its clipstack
1783 if (this->getGrContext()) {
1784 SkPath path;
1785 this->getClipStack()->asPath(&path);
1786 SkISize size = this->getBaseLayerSize();
1787 rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
1788 } else {
1789 *rgn = fMCRec->fRasterClip.forceGetBW();
1790 }
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001791}
1792
Brian Osman11052242016-10-27 14:47:55 -04001793GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001794 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001795 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001796}
1797
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001798GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001799 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001800 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001801}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001802
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001803void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1804 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001805 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001806 if (outer.isEmpty()) {
1807 return;
1808 }
1809 if (inner.isEmpty()) {
1810 this->drawRRect(outer, paint);
1811 return;
1812 }
1813
1814 // We don't have this method (yet), but technically this is what we should
1815 // be able to assert...
1816 // SkASSERT(outer.contains(inner));
1817 //
1818 // For now at least check for containment of bounds
1819 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1820
1821 this->onDrawDRRect(outer, inner, paint);
1822}
1823
reed41af9662015-01-05 07:49:08 -08001824// These need to stop being virtual -- clients need to override the onDraw... versions
1825
1826void SkCanvas::drawPaint(const SkPaint& paint) {
1827 this->onDrawPaint(paint);
1828}
1829
1830void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1831 this->onDrawRect(r, paint);
1832}
1833
msarettdca352e2016-08-26 06:37:45 -07001834void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1835 if (region.isEmpty()) {
1836 return;
1837 }
1838
1839 if (region.isRect()) {
1840 return this->drawIRect(region.getBounds(), paint);
1841 }
1842
1843 this->onDrawRegion(region, paint);
1844}
1845
reed41af9662015-01-05 07:49:08 -08001846void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1847 this->onDrawOval(r, paint);
1848}
1849
1850void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1851 this->onDrawRRect(rrect, paint);
1852}
1853
1854void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1855 this->onDrawPoints(mode, count, pts, paint);
1856}
1857
1858void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001859 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001860 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Brian Salomon199fb872017-02-06 09:41:10 -05001861 this->onDrawVertices(vmode, vertexCount, std::move(vertices), texs, colors, bmode, indices,
1862 indexCount, paint);
1863}
1864
1865void SkCanvas::drawVertices(sk_sp<SkVertices> vertices, SkBlendMode mode, const SkPaint& paint,
1866 uint32_t flags) {
1867 RETURN_ON_NULL(vertices);
1868 this->onDrawVerticesObject(std::move(vertices), mode, paint, flags);
reed41af9662015-01-05 07:49:08 -08001869}
1870
1871void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1872 this->onDrawPath(path, paint);
1873}
1874
reeda85d4d02015-05-06 12:56:48 -07001875void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001876 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001877 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001878}
1879
reede47829b2015-08-06 10:02:53 -07001880void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1881 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001882 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001883 if (dst.isEmpty() || src.isEmpty()) {
1884 return;
1885 }
1886 this->onDrawImageRect(image, &src, dst, paint, constraint);
1887}
reed41af9662015-01-05 07:49:08 -08001888
reed84984ef2015-07-17 07:09:43 -07001889void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1890 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001891 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001892 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001893}
1894
reede47829b2015-08-06 10:02:53 -07001895void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1896 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001897 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001898 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1899 constraint);
1900}
reede47829b2015-08-06 10:02:53 -07001901
reed4c21dc52015-06-25 12:32:03 -07001902void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1903 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001904 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001905 if (dst.isEmpty()) {
1906 return;
1907 }
msarett552bca92016-08-03 06:53:26 -07001908 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1909 this->onDrawImageNine(image, center, dst, paint);
1910 } else {
reede47829b2015-08-06 10:02:53 -07001911 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001912 }
reed4c21dc52015-06-25 12:32:03 -07001913}
1914
msarett16882062016-08-16 09:31:08 -07001915void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1916 const SkPaint* paint) {
1917 RETURN_ON_NULL(image);
1918 if (dst.isEmpty()) {
1919 return;
1920 }
msarett71df2d72016-09-30 12:41:42 -07001921
1922 SkIRect bounds;
1923 Lattice latticePlusBounds = lattice;
1924 if (!latticePlusBounds.fBounds) {
1925 bounds = SkIRect::MakeWH(image->width(), image->height());
1926 latticePlusBounds.fBounds = &bounds;
1927 }
1928
1929 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1930 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001931 } else {
1932 this->drawImageRect(image, dst, paint);
1933 }
1934}
1935
reed41af9662015-01-05 07:49:08 -08001936void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001937 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001938 return;
1939 }
reed41af9662015-01-05 07:49:08 -08001940 this->onDrawBitmap(bitmap, dx, dy, paint);
1941}
1942
reede47829b2015-08-06 10:02:53 -07001943void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001944 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001945 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001946 return;
1947 }
reede47829b2015-08-06 10:02:53 -07001948 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001949}
1950
reed84984ef2015-07-17 07:09:43 -07001951void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1952 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001953 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001954}
1955
reede47829b2015-08-06 10:02:53 -07001956void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1957 SrcRectConstraint constraint) {
1958 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1959 constraint);
1960}
reede47829b2015-08-06 10:02:53 -07001961
reed41af9662015-01-05 07:49:08 -08001962void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1963 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001964 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001965 return;
1966 }
msarett552bca92016-08-03 06:53:26 -07001967 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1968 this->onDrawBitmapNine(bitmap, center, dst, paint);
1969 } else {
reeda5517e22015-07-14 10:54:12 -07001970 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001971 }
reed41af9662015-01-05 07:49:08 -08001972}
1973
msarettc573a402016-08-02 08:05:56 -07001974void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1975 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001976 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001977 return;
1978 }
msarett71df2d72016-09-30 12:41:42 -07001979
1980 SkIRect bounds;
1981 Lattice latticePlusBounds = lattice;
1982 if (!latticePlusBounds.fBounds) {
1983 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1984 latticePlusBounds.fBounds = &bounds;
1985 }
1986
1987 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1988 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001989 } else {
msarett16882062016-08-16 09:31:08 -07001990 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001991 }
msarettc573a402016-08-02 08:05:56 -07001992}
1993
reed71c3c762015-06-24 10:29:17 -07001994void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001995 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07001996 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001997 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07001998 if (count <= 0) {
1999 return;
2000 }
Joe Gregorioc4859072017-01-20 14:21:27 +00002001 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002002 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002003 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002004}
2005
reedf70b5312016-03-04 16:36:20 -08002006void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2007 if (key) {
2008 this->onDrawAnnotation(rect, key, value);
2009 }
2010}
2011
reede47829b2015-08-06 10:02:53 -07002012void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2013 const SkPaint* paint, SrcRectConstraint constraint) {
2014 if (src) {
2015 this->drawImageRect(image, *src, dst, paint, constraint);
2016 } else {
2017 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2018 dst, paint, constraint);
2019 }
2020}
2021void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2022 const SkPaint* paint, SrcRectConstraint constraint) {
2023 if (src) {
2024 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2025 } else {
2026 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2027 dst, paint, constraint);
2028 }
2029}
2030
tomhudsoncb3bd182016-05-18 07:24:16 -07002031void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2032 SkIRect layer_bounds = this->getTopLayerBounds();
2033 if (matrix) {
2034 *matrix = this->getTotalMatrix();
2035 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2036 }
2037 if (clip_bounds) {
Mike Reed918e1442017-01-23 11:39:45 -05002038 *clip_bounds = this->getDeviceClipBounds();
tomhudsoncb3bd182016-05-18 07:24:16 -07002039 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2040 }
2041}
2042
reed@android.com8a1c16f2008-12-17 15:59:43 +00002043//////////////////////////////////////////////////////////////////////////////
2044// These are the virtual drawing methods
2045//////////////////////////////////////////////////////////////////////////////
2046
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002047void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002048 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002049 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2050 }
2051}
2052
reed41af9662015-01-05 07:49:08 -08002053void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002054 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002055 this->internalDrawPaint(paint);
2056}
2057
2058void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002059 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002060
2061 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002062 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002063 }
2064
reed@google.com4e2b3d32011-04-07 14:18:59 +00002065 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002066}
2067
reed41af9662015-01-05 07:49:08 -08002068void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2069 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002070 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002071 if ((long)count <= 0) {
2072 return;
2073 }
2074
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002075 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002076 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002077 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002078 // special-case 2 points (common for drawing a single line)
2079 if (2 == count) {
2080 r.set(pts[0], pts[1]);
2081 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002082 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002083 }
senorblanco87e066e2015-10-28 11:23:36 -07002084 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2085 return;
2086 }
2087 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002088 }
reed@google.coma584aed2012-05-16 14:06:02 +00002089
halcanary96fcdcc2015-08-27 07:41:13 -07002090 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002091
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002092 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002093
reed@android.com8a1c16f2008-12-17 15:59:43 +00002094 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002095 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002096 }
reed@google.com4b226022011-01-11 18:32:13 +00002097
reed@google.com4e2b3d32011-04-07 14:18:59 +00002098 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002099}
2100
reed4a167172016-08-18 17:15:25 -07002101static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2102 return ((intptr_t)paint.getImageFilter() |
2103#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2104 (intptr_t)canvas->getDrawFilter() |
2105#endif
2106 (intptr_t)paint.getLooper() ) != 0;
2107}
2108
reed41af9662015-01-05 07:49:08 -08002109void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002110 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002111 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002112 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002113 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002114 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2115 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2116 SkRect tmp(r);
2117 tmp.sort();
2118
senorblanco87e066e2015-10-28 11:23:36 -07002119 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2120 return;
2121 }
2122 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002123 }
reed@google.com4b226022011-01-11 18:32:13 +00002124
reed4a167172016-08-18 17:15:25 -07002125 if (needs_autodrawlooper(this, paint)) {
2126 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002127
reed4a167172016-08-18 17:15:25 -07002128 while (iter.next()) {
2129 iter.fDevice->drawRect(iter, r, looper.paint());
2130 }
2131
2132 LOOPER_END
2133 } else {
2134 this->predrawNotify(bounds, &paint, false);
2135 SkDrawIter iter(this);
2136 while (iter.next()) {
2137 iter.fDevice->drawRect(iter, r, paint);
2138 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002139 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002140}
2141
msarett44df6512016-08-25 13:54:30 -07002142void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2143 SkRect storage;
2144 SkRect regionRect = SkRect::Make(region.getBounds());
2145 const SkRect* bounds = nullptr;
2146 if (paint.canComputeFastBounds()) {
2147 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2148 return;
2149 }
2150 bounds = &regionRect;
2151 }
2152
2153 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2154
2155 while (iter.next()) {
2156 iter.fDevice->drawRegion(iter, region, looper.paint());
2157 }
2158
2159 LOOPER_END
2160}
2161
reed41af9662015-01-05 07:49:08 -08002162void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002163 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002164 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002165 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002166 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002167 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2168 return;
2169 }
2170 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002171 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002172
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002173 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002174
2175 while (iter.next()) {
2176 iter.fDevice->drawOval(iter, oval, looper.paint());
2177 }
2178
2179 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002180}
2181
bsalomonac3aa242016-08-19 11:25:19 -07002182void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2183 SkScalar sweepAngle, bool useCenter,
2184 const SkPaint& paint) {
2185 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2186 const SkRect* bounds = nullptr;
2187 if (paint.canComputeFastBounds()) {
2188 SkRect storage;
2189 // Note we're using the entire oval as the bounds.
2190 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2191 return;
2192 }
2193 bounds = &oval;
2194 }
2195
2196 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2197
2198 while (iter.next()) {
2199 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2200 }
2201
2202 LOOPER_END
2203}
2204
reed41af9662015-01-05 07:49:08 -08002205void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002206 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002207 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002208 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002209 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002210 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2211 return;
2212 }
2213 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002214 }
2215
2216 if (rrect.isRect()) {
2217 // call the non-virtual version
2218 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002219 return;
2220 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002221 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002222 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2223 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002224 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002225
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002226 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002227
2228 while (iter.next()) {
2229 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2230 }
2231
2232 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002233}
2234
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002235void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2236 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002237 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002238 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002239 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002240 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2241 return;
2242 }
2243 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002244 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002245
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002246 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002247
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002248 while (iter.next()) {
2249 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2250 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002251
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002252 LOOPER_END
2253}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002254
reed41af9662015-01-05 07:49:08 -08002255void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002256 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002257 if (!path.isFinite()) {
2258 return;
2259 }
2260
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002261 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002262 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002263 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002264 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002265 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2266 return;
2267 }
2268 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002269 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002270
2271 const SkRect& r = path.getBounds();
2272 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002273 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002274 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002275 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002276 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002277 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002278
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002279 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002280
2281 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002282 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002283 }
2284
reed@google.com4e2b3d32011-04-07 14:18:59 +00002285 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002286}
2287
reed262a71b2015-12-05 13:07:27 -08002288bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002289 if (!paint.getImageFilter()) {
2290 return false;
2291 }
2292
2293 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002294 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002295 return false;
2296 }
2297
2298 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2299 // Once we can filter and the filter will return a result larger than itself, we should be
2300 // able to remove this constraint.
2301 // skbug.com/4526
2302 //
2303 SkPoint pt;
2304 ctm.mapXY(x, y, &pt);
2305 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2306 return ir.contains(fMCRec->fRasterClip.getBounds());
2307}
2308
reeda85d4d02015-05-06 12:56:48 -07002309void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002310 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002311 SkRect bounds = SkRect::MakeXYWH(x, y,
2312 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002313 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002314 SkRect tmp = bounds;
2315 if (paint) {
2316 paint->computeFastBounds(tmp, &tmp);
2317 }
2318 if (this->quickReject(tmp)) {
2319 return;
2320 }
reeda85d4d02015-05-06 12:56:48 -07002321 }
halcanary9d524f22016-03-29 09:03:52 -07002322
reeda85d4d02015-05-06 12:56:48 -07002323 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002324 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002325 paint = lazy.init();
2326 }
reed262a71b2015-12-05 13:07:27 -08002327
reeda2217ef2016-07-20 06:04:34 -07002328 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002329 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2330 *paint);
2331 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002332 special = this->getDevice()->makeSpecial(image);
2333 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002334 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002335 }
2336 }
2337
reed262a71b2015-12-05 13:07:27 -08002338 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2339
reeda85d4d02015-05-06 12:56:48 -07002340 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002341 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002342 if (special) {
2343 SkPoint pt;
2344 iter.fMatrix->mapXY(x, y, &pt);
2345 iter.fDevice->drawSpecial(iter, special.get(),
2346 SkScalarRoundToInt(pt.fX),
2347 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002348 } else {
2349 iter.fDevice->drawImage(iter, image, x, y, pnt);
2350 }
reeda85d4d02015-05-06 12:56:48 -07002351 }
halcanary9d524f22016-03-29 09:03:52 -07002352
reeda85d4d02015-05-06 12:56:48 -07002353 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002354}
2355
reed41af9662015-01-05 07:49:08 -08002356void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002357 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002358 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002359 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002360 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002361 if (paint) {
2362 paint->computeFastBounds(dst, &storage);
2363 }
2364 if (this->quickReject(storage)) {
2365 return;
2366 }
reeda85d4d02015-05-06 12:56:48 -07002367 }
2368 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002369 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002370 paint = lazy.init();
2371 }
halcanary9d524f22016-03-29 09:03:52 -07002372
senorblancoc41e7e12015-12-07 12:51:30 -08002373 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002374 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002375
reeda85d4d02015-05-06 12:56:48 -07002376 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002377 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002378 }
halcanary9d524f22016-03-29 09:03:52 -07002379
reeda85d4d02015-05-06 12:56:48 -07002380 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002381}
2382
reed41af9662015-01-05 07:49:08 -08002383void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002384 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002385 SkDEBUGCODE(bitmap.validate();)
2386
reed33366972015-10-08 09:22:02 -07002387 if (bitmap.drawsNothing()) {
2388 return;
2389 }
2390
2391 SkLazyPaint lazy;
2392 if (nullptr == paint) {
2393 paint = lazy.init();
2394 }
2395
2396 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2397
2398 SkRect storage;
2399 const SkRect* bounds = nullptr;
2400 if (paint->canComputeFastBounds()) {
2401 bitmap.getBounds(&storage);
2402 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002403 SkRect tmp = storage;
2404 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2405 return;
2406 }
2407 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002408 }
reed@google.com4b226022011-01-11 18:32:13 +00002409
reeda2217ef2016-07-20 06:04:34 -07002410 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002411 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2412 *paint);
2413 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002414 special = this->getDevice()->makeSpecial(bitmap);
2415 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002416 drawAsSprite = false;
2417 }
2418 }
2419
reed262a71b2015-12-05 13:07:27 -08002420 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002421
2422 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002423 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002424 if (special) {
reed262a71b2015-12-05 13:07:27 -08002425 SkPoint pt;
2426 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002427 iter.fDevice->drawSpecial(iter, special.get(),
2428 SkScalarRoundToInt(pt.fX),
2429 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002430 } else {
2431 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2432 }
reed33366972015-10-08 09:22:02 -07002433 }
msarettfbfa2582016-08-12 08:29:08 -07002434
reed33366972015-10-08 09:22:02 -07002435 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002436}
2437
reed@google.com9987ec32011-09-07 11:57:52 +00002438// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002439void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002440 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002441 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002442 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002443 return;
2444 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002445
halcanary96fcdcc2015-08-27 07:41:13 -07002446 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002447 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002448 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2449 return;
2450 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002451 }
reed@google.com3d608122011-11-21 15:16:16 +00002452
reed@google.com33535f32012-09-25 15:37:50 +00002453 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002454 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002455 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002456 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002457
senorblancoc41e7e12015-12-07 12:51:30 -08002458 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002459 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002460
reed@google.com33535f32012-09-25 15:37:50 +00002461 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002462 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002463 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002464
reed@google.com33535f32012-09-25 15:37:50 +00002465 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002466}
2467
reed41af9662015-01-05 07:49:08 -08002468void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002469 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002470 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002471 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002472 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002473}
2474
reed4c21dc52015-06-25 12:32:03 -07002475void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2476 const SkPaint* paint) {
2477 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002478
halcanary96fcdcc2015-08-27 07:41:13 -07002479 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002480 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002481 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2482 return;
2483 }
reed@google.com3d608122011-11-21 15:16:16 +00002484 }
halcanary9d524f22016-03-29 09:03:52 -07002485
reed4c21dc52015-06-25 12:32:03 -07002486 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002487 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002488 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002489 }
halcanary9d524f22016-03-29 09:03:52 -07002490
senorblancoc41e7e12015-12-07 12:51:30 -08002491 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002492
reed4c21dc52015-06-25 12:32:03 -07002493 while (iter.next()) {
2494 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002495 }
halcanary9d524f22016-03-29 09:03:52 -07002496
reed4c21dc52015-06-25 12:32:03 -07002497 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002498}
2499
reed41af9662015-01-05 07:49:08 -08002500void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2501 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002502 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002503 SkDEBUGCODE(bitmap.validate();)
2504
halcanary96fcdcc2015-08-27 07:41:13 -07002505 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002506 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002507 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2508 return;
2509 }
reed4c21dc52015-06-25 12:32:03 -07002510 }
halcanary9d524f22016-03-29 09:03:52 -07002511
reed4c21dc52015-06-25 12:32:03 -07002512 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002513 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002514 paint = lazy.init();
2515 }
halcanary9d524f22016-03-29 09:03:52 -07002516
senorblancoc41e7e12015-12-07 12:51:30 -08002517 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002518
reed4c21dc52015-06-25 12:32:03 -07002519 while (iter.next()) {
2520 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2521 }
halcanary9d524f22016-03-29 09:03:52 -07002522
reed4c21dc52015-06-25 12:32:03 -07002523 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002524}
2525
msarett16882062016-08-16 09:31:08 -07002526void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2527 const SkPaint* paint) {
2528 if (nullptr == paint || paint->canComputeFastBounds()) {
2529 SkRect storage;
2530 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2531 return;
2532 }
2533 }
2534
2535 SkLazyPaint lazy;
2536 if (nullptr == paint) {
2537 paint = lazy.init();
2538 }
2539
2540 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2541
2542 while (iter.next()) {
2543 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2544 }
2545
2546 LOOPER_END
2547}
2548
2549void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2550 const SkRect& dst, const SkPaint* paint) {
2551 if (nullptr == paint || paint->canComputeFastBounds()) {
2552 SkRect storage;
2553 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2554 return;
2555 }
2556 }
2557
2558 SkLazyPaint lazy;
2559 if (nullptr == paint) {
2560 paint = lazy.init();
2561 }
2562
2563 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2564
2565 while (iter.next()) {
2566 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2567 }
2568
2569 LOOPER_END
2570}
2571
reed@google.comf67e4cf2011-03-15 20:56:58 +00002572class SkDeviceFilteredPaint {
2573public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002574 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002575 uint32_t filteredFlags = device->filterTextFlags(paint);
2576 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002577 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002578 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002579 fPaint = newPaint;
2580 } else {
2581 fPaint = &paint;
2582 }
2583 }
2584
reed@google.comf67e4cf2011-03-15 20:56:58 +00002585 const SkPaint& paint() const { return *fPaint; }
2586
2587private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002588 const SkPaint* fPaint;
2589 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002590};
2591
bungeman@google.com52c748b2011-08-22 21:30:43 +00002592void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2593 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002594 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002595 draw.fDevice->drawRect(draw, r, paint);
2596 } else {
2597 SkPaint p(paint);
Mike Reeda99b6ce2017-02-04 11:04:26 -05002598 p.setStrokeWidth(textSize * paint.getStrokeWidth());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002599 draw.fDevice->drawRect(draw, r, p);
2600 }
2601}
2602
2603void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2604 const char text[], size_t byteLength,
2605 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002606 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002607
2608 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002609 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002610 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002611 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002612 return;
2613 }
2614
2615 SkScalar width = 0;
2616 SkPoint start;
2617
2618 start.set(0, 0); // to avoid warning
2619 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2620 SkPaint::kStrikeThruText_Flag)) {
2621 width = paint.measureText(text, byteLength);
2622
2623 SkScalar offsetX = 0;
2624 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2625 offsetX = SkScalarHalf(width);
2626 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2627 offsetX = width;
2628 }
2629 start.set(x - offsetX, y);
2630 }
2631
2632 if (0 == width) {
2633 return;
2634 }
2635
2636 uint32_t flags = paint.getFlags();
2637
2638 if (flags & (SkPaint::kUnderlineText_Flag |
2639 SkPaint::kStrikeThruText_Flag)) {
2640 SkScalar textSize = paint.getTextSize();
Mike Reeda99b6ce2017-02-04 11:04:26 -05002641 SkScalar height = textSize * kStdUnderline_Thickness;
bungeman@google.com52c748b2011-08-22 21:30:43 +00002642 SkRect r;
2643
2644 r.fLeft = start.fX;
2645 r.fRight = start.fX + width;
2646
2647 if (flags & SkPaint::kUnderlineText_Flag) {
Mike Reeda99b6ce2017-02-04 11:04:26 -05002648 SkScalar offset = textSize * kStdUnderline_Offset + start.fY;
bungeman@google.com52c748b2011-08-22 21:30:43 +00002649 r.fTop = offset;
2650 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002651 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002652 }
2653 if (flags & SkPaint::kStrikeThruText_Flag) {
Mike Reeda99b6ce2017-02-04 11:04:26 -05002654 SkScalar offset = textSize * kStdStrikeThru_Offset + start.fY;
bungeman@google.com52c748b2011-08-22 21:30:43 +00002655 r.fTop = offset;
2656 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002657 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002658 }
2659 }
2660}
2661
reed@google.come0d9ce82014-04-23 04:00:17 +00002662void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2663 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002664 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002665
2666 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002667 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002668 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002669 DrawTextDecorations(iter, dfp.paint(),
2670 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002671 }
2672
reed@google.com4e2b3d32011-04-07 14:18:59 +00002673 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002674}
2675
reed@google.come0d9ce82014-04-23 04:00:17 +00002676void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2677 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002678 SkPoint textOffset = SkPoint::Make(0, 0);
2679
halcanary96fcdcc2015-08-27 07:41:13 -07002680 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002681
reed@android.com8a1c16f2008-12-17 15:59:43 +00002682 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002683 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002684 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002685 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002686 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002687
reed@google.com4e2b3d32011-04-07 14:18:59 +00002688 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002689}
2690
reed@google.come0d9ce82014-04-23 04:00:17 +00002691void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2692 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002693
2694 SkPoint textOffset = SkPoint::Make(0, constY);
2695
halcanary96fcdcc2015-08-27 07:41:13 -07002696 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002697
reed@android.com8a1c16f2008-12-17 15:59:43 +00002698 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002699 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002700 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002701 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002702 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002703
reed@google.com4e2b3d32011-04-07 14:18:59 +00002704 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002705}
2706
reed@google.come0d9ce82014-04-23 04:00:17 +00002707void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2708 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002709 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002710
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711 while (iter.next()) {
2712 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002713 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002714 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002715
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002716 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002717}
2718
reed45561a02016-07-07 12:47:17 -07002719void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2720 const SkRect* cullRect, const SkPaint& paint) {
2721 if (cullRect && this->quickReject(*cullRect)) {
2722 return;
2723 }
2724
2725 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2726
2727 while (iter.next()) {
2728 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2729 }
2730
2731 LOOPER_END
2732}
2733
fmalita00d5c2c2014-08-21 08:53:26 -07002734void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2735 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002736
fmalita85d5eb92015-03-04 11:20:12 -08002737 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002738 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002739 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002740 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002741 SkRect tmp;
2742 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2743 return;
2744 }
2745 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002746 }
2747
fmalita024f9962015-03-03 19:08:17 -08002748 // We cannot filter in the looper as we normally do, because the paint is
2749 // incomplete at this point (text-related attributes are embedded within blob run paints).
2750 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002751 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002752
fmalita85d5eb92015-03-04 11:20:12 -08002753 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002754
fmalitaaa1b9122014-08-28 14:32:24 -07002755 while (iter.next()) {
2756 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002757 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002758 }
2759
fmalitaaa1b9122014-08-28 14:32:24 -07002760 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002761
2762 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002763}
2764
reed@google.come0d9ce82014-04-23 04:00:17 +00002765// These will become non-virtual, so they always call the (virtual) onDraw... method
2766void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2767 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002768 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002769 if (byteLength) {
2770 this->onDrawText(text, byteLength, x, y, paint);
2771 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002772}
2773void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2774 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002775 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002776 if (byteLength) {
2777 this->onDrawPosText(text, byteLength, pos, paint);
2778 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002779}
2780void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2781 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002782 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002783 if (byteLength) {
2784 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2785 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002786}
2787void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2788 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002789 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002790 if (byteLength) {
2791 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2792 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002793}
reed45561a02016-07-07 12:47:17 -07002794void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2795 const SkRect* cullRect, const SkPaint& paint) {
2796 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2797 if (byteLength) {
2798 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2799 }
2800}
fmalita00d5c2c2014-08-21 08:53:26 -07002801void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2802 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002803 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002804 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002805 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002806}
reed@google.come0d9ce82014-04-23 04:00:17 +00002807
reed41af9662015-01-05 07:49:08 -08002808void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2809 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002810 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002811 const uint16_t indices[], int indexCount,
2812 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002813 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002814 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002815
reed@android.com8a1c16f2008-12-17 15:59:43 +00002816 while (iter.next()) {
2817 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002818 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002819 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002820 }
reed@google.com4b226022011-01-11 18:32:13 +00002821
reed@google.com4e2b3d32011-04-07 14:18:59 +00002822 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823}
2824
Brian Salomon199fb872017-02-06 09:41:10 -05002825void SkCanvas::onDrawVerticesObject(sk_sp<SkVertices> vertices, SkBlendMode bmode,
2826 const SkPaint& paint, uint32_t flags) {
2827 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2828 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2829
2830 while (iter.next()) {
2831 // In the common case of one iteration we could std::move vertices here.
2832 iter.fDevice->drawVerticesObject(iter, vertices, bmode, looper.paint(), flags);
2833 }
2834
2835 LOOPER_END
2836}
2837
2838void SkCanvas::onDrawVerticesObjectFallback(sk_sp<SkVertices> vertices, SkBlendMode mode,
2839 const SkPaint& paint, uint32_t flags) {
2840 const SkPoint* texs =
2841 (flags & SkCanvas::kIgnoreTexCoords_VerticesFlag) ? nullptr : vertices->texCoords();
2842 const SkColor* colors = (flags & kIgnoreColors_VerticesFlag) ? nullptr : vertices->colors();
2843 this->onDrawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), texs,
2844 colors, mode, vertices->indices(), vertices->indexCount(), paint);
2845}
2846
dandovb3c9d1c2014-08-12 08:34:29 -07002847void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002848 const SkPoint texCoords[4], SkBlendMode bmode,
2849 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002850 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002851 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002852 return;
2853 }
mtklein6cfa73a2014-08-13 13:33:49 -07002854
Mike Reedfaba3712016-11-03 14:45:31 -04002855 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002856}
2857
2858void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002859 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002860 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002861 // Since a patch is always within the convex hull of the control points, we discard it when its
2862 // bounding rectangle is completely outside the current clip.
2863 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002864 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002865 if (this->quickReject(bounds)) {
2866 return;
2867 }
mtklein6cfa73a2014-08-13 13:33:49 -07002868
halcanary96fcdcc2015-08-27 07:41:13 -07002869 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002870
dandovecfff212014-08-04 10:02:00 -07002871 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002872 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002873 }
mtklein6cfa73a2014-08-13 13:33:49 -07002874
dandovecfff212014-08-04 10:02:00 -07002875 LOOPER_END
2876}
2877
reeda8db7282015-07-07 10:22:31 -07002878void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002879 RETURN_ON_NULL(dr);
2880 if (x || y) {
2881 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2882 this->onDrawDrawable(dr, &matrix);
2883 } else {
2884 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002885 }
2886}
2887
reeda8db7282015-07-07 10:22:31 -07002888void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002889 RETURN_ON_NULL(dr);
2890 if (matrix && matrix->isIdentity()) {
2891 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002892 }
reede3b38ce2016-01-08 09:18:44 -08002893 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002894}
2895
2896void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002897 // drawable bounds are no longer reliable (e.g. android displaylist)
2898 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002899 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002900}
2901
reed71c3c762015-06-24 10:29:17 -07002902void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002903 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002904 const SkRect* cull, const SkPaint* paint) {
2905 if (cull && this->quickReject(*cull)) {
2906 return;
2907 }
2908
2909 SkPaint pnt;
2910 if (paint) {
2911 pnt = *paint;
2912 }
halcanary9d524f22016-03-29 09:03:52 -07002913
halcanary96fcdcc2015-08-27 07:41:13 -07002914 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002915 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002916 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002917 }
2918 LOOPER_END
2919}
2920
reedf70b5312016-03-04 16:36:20 -08002921void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2922 SkASSERT(key);
2923
2924 SkPaint paint;
2925 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2926 while (iter.next()) {
2927 iter.fDevice->drawAnnotation(iter, rect, key, value);
2928 }
2929 LOOPER_END
2930}
2931
reed@android.com8a1c16f2008-12-17 15:59:43 +00002932//////////////////////////////////////////////////////////////////////////////
2933// These methods are NOT virtual, and therefore must call back into virtual
2934// methods, rather than actually drawing themselves.
2935//////////////////////////////////////////////////////////////////////////////
2936
reed374772b2016-10-05 17:33:02 -07002937void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002938 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002939 SkPaint paint;
2940
2941 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002942 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002943 this->drawPaint(paint);
2944}
2945
reed374772b2016-10-05 17:33:02 -07002946void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002947 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002948 SkPaint paint;
2949
2950 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002951 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002952 this->drawPaint(paint);
2953}
2954
2955void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002956 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002957 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002958
reed@android.com8a1c16f2008-12-17 15:59:43 +00002959 pt.set(x, y);
2960 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2961}
2962
2963void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002964 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002965 SkPoint pt;
2966 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002967
reed@android.com8a1c16f2008-12-17 15:59:43 +00002968 pt.set(x, y);
2969 paint.setColor(color);
2970 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2971}
2972
2973void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2974 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002975 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002976 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002977
reed@android.com8a1c16f2008-12-17 15:59:43 +00002978 pts[0].set(x0, y0);
2979 pts[1].set(x1, y1);
2980 this->drawPoints(kLines_PointMode, 2, pts, paint);
2981}
2982
2983void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2984 SkScalar right, SkScalar bottom,
2985 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002986 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002987 SkRect r;
2988
2989 r.set(left, top, right, bottom);
2990 this->drawRect(r, paint);
2991}
2992
2993void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2994 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002995 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002996 if (radius < 0) {
2997 radius = 0;
2998 }
2999
3000 SkRect r;
3001 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003002 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003003}
3004
3005void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3006 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003007 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003008 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003009 SkRRect rrect;
3010 rrect.setRectXY(r, rx, ry);
3011 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003012 } else {
3013 this->drawRect(r, paint);
3014 }
3015}
3016
reed@android.com8a1c16f2008-12-17 15:59:43 +00003017void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3018 SkScalar sweepAngle, bool useCenter,
3019 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003020 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003021 if (oval.isEmpty() || !sweepAngle) {
3022 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003023 }
bsalomon21af9ca2016-08-25 12:29:23 -07003024 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003025}
3026
3027void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3028 const SkPath& path, SkScalar hOffset,
3029 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003030 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003031 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003032
reed@android.com8a1c16f2008-12-17 15:59:43 +00003033 matrix.setTranslate(hOffset, vOffset);
3034 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3035}
3036
reed@android.comf76bacf2009-05-13 14:00:33 +00003037///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003038
3039/**
3040 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3041 * against the playback cost of recursing into the subpicture to get at its actual ops.
3042 *
3043 * For now we pick a conservatively small value, though measurement (and other heuristics like
3044 * the type of ops contained) may justify changing this value.
3045 */
3046#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003047
reedd5fa1a42014-08-09 11:08:05 -07003048void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003049 RETURN_ON_NULL(picture);
3050
reed1c2c4412015-04-30 13:09:24 -07003051 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003052 if (matrix && matrix->isIdentity()) {
3053 matrix = nullptr;
3054 }
3055 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3056 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3057 picture->playback(this);
3058 } else {
3059 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003060 }
3061}
robertphillips9b14f262014-06-04 05:40:44 -07003062
reedd5fa1a42014-08-09 11:08:05 -07003063void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3064 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003065 if (!paint || paint->canComputeFastBounds()) {
3066 SkRect bounds = picture->cullRect();
3067 if (paint) {
3068 paint->computeFastBounds(bounds, &bounds);
3069 }
3070 if (matrix) {
3071 matrix->mapRect(&bounds);
3072 }
3073 if (this->quickReject(bounds)) {
3074 return;
3075 }
3076 }
3077
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003078 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003079 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003080}
3081
vjiaoblack95302da2016-07-21 10:25:54 -07003082#ifdef SK_EXPERIMENTAL_SHADOWING
3083void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3084 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003085 const SkPaint* paint,
3086 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003087 RETURN_ON_NULL(picture);
3088
3089 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3090
vjiaoblacke6f5d562016-08-25 06:30:23 -07003091 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003092}
3093
3094void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3095 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003096 const SkPaint* paint,
3097 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003098 if (!paint || paint->canComputeFastBounds()) {
3099 SkRect bounds = picture->cullRect();
3100 if (paint) {
3101 paint->computeFastBounds(bounds, &bounds);
3102 }
3103 if (matrix) {
3104 matrix->mapRect(&bounds);
3105 }
3106 if (this->quickReject(bounds)) {
3107 return;
3108 }
3109 }
3110
3111 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3112
vjiaoblacke6f5d562016-08-25 06:30:23 -07003113 sk_sp<SkImage> povDepthMap;
3114 sk_sp<SkImage> diffuseMap;
3115
vjiaoblack904527d2016-08-09 09:32:09 -07003116 // povDepthMap
3117 {
3118 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003119 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3120 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003121 sk_sp<SkLights> povLight = builder.finish();
3122
3123 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3124 picture->cullRect().height(),
3125 kBGRA_8888_SkColorType,
3126 kOpaque_SkAlphaType);
3127
3128 // Create a new surface (that matches the backend of canvas)
3129 // to create the povDepthMap
3130 sk_sp<SkSurface> surf(this->makeSurface(info));
3131
3132 // Wrap another SPFCanvas around the surface
3133 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3134 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3135
3136 // set the depth map canvas to have the light as the user's POV
3137 depthMapCanvas->setLights(std::move(povLight));
3138
3139 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003140 povDepthMap = surf->makeImageSnapshot();
3141 }
3142
3143 // diffuseMap
3144 {
3145 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3146 picture->cullRect().height(),
3147 kBGRA_8888_SkColorType,
3148 kOpaque_SkAlphaType);
3149
3150 sk_sp<SkSurface> surf(this->makeSurface(info));
3151 surf->getCanvas()->drawPicture(picture);
3152
3153 diffuseMap = surf->makeImageSnapshot();
3154 }
vjiaoblack904527d2016-08-09 09:32:09 -07003155
3156 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3157 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003158 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3159 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003160
3161 // TODO: pass the depth to the shader in vertices, or uniforms
3162 // so we don't have to render depth and color separately
3163 for (int i = 0; i < fLights->numLights(); ++i) {
3164 // skip over ambient lights; they don't cast shadows
3165 // lights that have shadow maps do not need updating (because lights are immutable)
3166 sk_sp<SkImage> depthMap;
3167 SkISize shMapSize;
3168
3169 if (fLights->light(i).getShadowMap() != nullptr) {
3170 continue;
3171 }
3172
3173 if (fLights->light(i).isRadial()) {
3174 shMapSize.fHeight = 1;
3175 shMapSize.fWidth = (int) picture->cullRect().width();
3176
3177 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3178 kBGRA_8888_SkColorType,
3179 kOpaque_SkAlphaType);
3180
3181 // Create new surface (that matches the backend of canvas)
3182 // for each shadow map
3183 sk_sp<SkSurface> surf(this->makeSurface(info));
3184
3185 // Wrap another SPFCanvas around the surface
3186 SkCanvas* depthMapCanvas = surf->getCanvas();
3187
3188 SkLights::Builder builder;
3189 builder.add(fLights->light(i));
3190 sk_sp<SkLights> curLight = builder.finish();
3191
3192 sk_sp<SkShader> shadowMapShader;
3193 shadowMapShader = SkRadialShadowMapShader::Make(
3194 povDepthShader, curLight,
3195 (int) picture->cullRect().width(),
3196 (int) picture->cullRect().height());
3197
3198 SkPaint shadowMapPaint;
3199 shadowMapPaint.setShader(std::move(shadowMapShader));
3200
3201 depthMapCanvas->setLights(curLight);
3202
3203 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3204 diffuseMap->height()),
3205 shadowMapPaint);
3206
3207 depthMap = surf->makeImageSnapshot();
3208
3209 } else {
3210 // TODO: compute the correct size of the depth map from the light properties
3211 // TODO: maybe add a kDepth_8_SkColorType
3212 // TODO: find actual max depth of picture
3213 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3214 fLights->light(i), 255,
3215 (int) picture->cullRect().width(),
3216 (int) picture->cullRect().height());
3217
3218 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3219 kBGRA_8888_SkColorType,
3220 kOpaque_SkAlphaType);
3221
3222 // Create a new surface (that matches the backend of canvas)
3223 // for each shadow map
3224 sk_sp<SkSurface> surf(this->makeSurface(info));
3225
3226 // Wrap another SPFCanvas around the surface
3227 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3228 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3229 depthMapCanvas->setShadowParams(params);
3230
3231 // set the depth map canvas to have the light we're drawing.
3232 SkLights::Builder builder;
3233 builder.add(fLights->light(i));
3234 sk_sp<SkLights> curLight = builder.finish();
3235 depthMapCanvas->setLights(std::move(curLight));
3236
3237 depthMapCanvas->drawPicture(picture);
3238 depthMap = surf->makeImageSnapshot();
3239 }
3240
3241 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3242 fLights->light(i).setShadowMap(std::move(depthMap));
3243 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3244 // we blur the variance map
3245 SkPaint blurPaint;
3246 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3247 params.fShadowRadius, nullptr));
3248
3249 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3250 kBGRA_8888_SkColorType,
3251 kOpaque_SkAlphaType);
3252
3253 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3254
3255 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3256
3257 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3258 }
3259 }
3260
3261 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003262 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3263 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003264 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003265 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003266 diffuseMap->height(),
3267 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003268
3269 shadowPaint.setShader(shadowShader);
3270
3271 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003272}
3273#endif
3274
reed@android.com8a1c16f2008-12-17 15:59:43 +00003275///////////////////////////////////////////////////////////////////////////////
3276///////////////////////////////////////////////////////////////////////////////
3277
reed3aafe112016-08-18 12:45:34 -07003278SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003279 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003280
3281 SkASSERT(canvas);
3282
reed3aafe112016-08-18 12:45:34 -07003283 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003284 fDone = !fImpl->next();
3285}
3286
3287SkCanvas::LayerIter::~LayerIter() {
3288 fImpl->~SkDrawIter();
3289}
3290
3291void SkCanvas::LayerIter::next() {
3292 fDone = !fImpl->next();
3293}
3294
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003295SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003296 return fImpl->getDevice();
3297}
3298
3299const SkMatrix& SkCanvas::LayerIter::matrix() const {
3300 return fImpl->getMatrix();
3301}
3302
3303const SkPaint& SkCanvas::LayerIter::paint() const {
3304 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003305 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003306 paint = &fDefaultPaint;
3307 }
3308 return *paint;
3309}
3310
reed1e7f5e72016-04-27 07:49:17 -07003311const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003312int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3313int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003314
3315///////////////////////////////////////////////////////////////////////////////
3316
fmalitac3b589a2014-06-05 12:40:07 -07003317SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003318
3319///////////////////////////////////////////////////////////////////////////////
3320
3321static bool supported_for_raster_canvas(const SkImageInfo& info) {
3322 switch (info.alphaType()) {
3323 case kPremul_SkAlphaType:
3324 case kOpaque_SkAlphaType:
3325 break;
3326 default:
3327 return false;
3328 }
3329
3330 switch (info.colorType()) {
3331 case kAlpha_8_SkColorType:
3332 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003333 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003334 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003335 break;
3336 default:
3337 return false;
3338 }
3339
3340 return true;
3341}
3342
Mike Reed5df49342016-11-12 08:06:55 -06003343std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3344 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003345 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003346 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003347 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003348
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003349 SkBitmap bitmap;
3350 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003351 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003352 }
Mike Reed5df49342016-11-12 08:06:55 -06003353 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003354}
reedd5fa1a42014-08-09 11:08:05 -07003355
3356///////////////////////////////////////////////////////////////////////////////
3357
3358SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003359 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003360 : fCanvas(canvas)
3361 , fSaveCount(canvas->getSaveCount())
3362{
bsalomon49f085d2014-09-05 13:34:00 -07003363 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003364 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003365 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003366 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003367 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003368 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003369 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003370 canvas->save();
3371 }
mtklein6cfa73a2014-08-13 13:33:49 -07003372
bsalomon49f085d2014-09-05 13:34:00 -07003373 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003374 canvas->concat(*matrix);
3375 }
3376}
3377
3378SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3379 fCanvas->restoreToCount(fSaveCount);
3380}
reede8f30622016-03-23 18:59:25 -07003381
Florin Malitaee424ac2016-12-01 12:47:59 -05003382///////////////////////////////////////////////////////////////////////////////
3383
3384SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3385 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3386
Florin Malita439ace92016-12-02 12:05:41 -05003387SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3388 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3389
Florin Malitaee424ac2016-12-01 12:47:59 -05003390SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3391 (void)this->INHERITED::getSaveLayerStrategy(rec);
3392 return kNoLayer_SaveLayerStrategy;
3393}
3394
3395///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003396
reed73603f32016-09-20 08:42:38 -07003397static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3398static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3399static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3400static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3401static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3402static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003403
3404///////////////////////////////////////////////////////////////////////////////////////////////////
3405
3406SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3407 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3408 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3409 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3410 SkIPoint origin = dev->getOrigin();
3411 SkMatrix ctm = this->getTotalMatrix();
3412 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3413
3414 SkIRect clip = fMCRec->fRasterClip.getBounds();
3415 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003416 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003417 clip.setEmpty();
3418 }
3419
3420 fAllocator->updateHandle(handle, ctm, clip);
3421 return handle;
3422 }
3423 return nullptr;
3424}
3425
3426static bool install(SkBitmap* bm, const SkImageInfo& info,
3427 const SkRasterHandleAllocator::Rec& rec) {
3428 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3429 rec.fReleaseProc, rec.fReleaseCtx);
3430}
3431
3432SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3433 SkBitmap* bm) {
3434 SkRasterHandleAllocator::Rec rec;
3435 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3436 return nullptr;
3437 }
3438 return rec.fHandle;
3439}
3440
3441std::unique_ptr<SkCanvas>
3442SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3443 const SkImageInfo& info, const Rec* rec) {
3444 if (!alloc || !supported_for_raster_canvas(info)) {
3445 return nullptr;
3446 }
3447
3448 SkBitmap bm;
3449 Handle hndl;
3450
3451 if (rec) {
3452 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3453 } else {
3454 hndl = alloc->allocBitmap(info, &bm);
3455 }
3456 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3457}