blob: 47160531974a2f5cef8859173fd464efda2eef40 [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
bungemand3ebb482015-08-05 13:57:49 -07008#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"
reed96472de2014-12-10 09:53:42 -080033#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000034#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070035#include "SkShadowPaintFilterCanvas.h"
36#include "SkShadowShader.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000037#include "SkSmallAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080038#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000039#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070040#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000041#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000042#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080043#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070044#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000045
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000046#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080047#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070049#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070050
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000051#endif
Mike Reedebfce6d2016-12-12 10:02:12 -050052#include "SkClipOpPriv.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 Reed5e257172016-11-01 11:22:05 -0400488 tmp.setImageFilter(sk_ref_sp(fPaint->getImageFilter()));
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
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000856SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000857 if (updateMatrixClip) {
858 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
859 }
reed@google.com9266fed2011-03-30 00:18:03 +0000860 return fMCRec->fTopLayer->fDevice;
861}
862
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000863bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700864 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000865 return false;
866 }
867
868 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700869 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700870 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000871 return false;
872 }
873 weAllocated = true;
874 }
875
reedcf01e312015-05-23 19:14:51 -0700876 SkAutoPixmapUnlock unlocker;
877 if (bitmap->requestLock(&unlocker)) {
878 const SkPixmap& pm = unlocker.pixmap();
879 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
880 return true;
881 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000882 }
883
884 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500885 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000886 }
887 return false;
888}
reed@google.com51df9e32010-12-23 19:29:18 +0000889
bsalomon@google.comc6980972011-11-02 19:57:21 +0000890bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000891 SkIRect r = srcRect;
892 const SkISize size = this->getBaseLayerSize();
893 if (!r.intersect(0, 0, size.width(), size.height())) {
894 bitmap->reset();
895 return false;
896 }
897
reed84825042014-09-02 12:50:45 -0700898 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000899 // bitmap will already be reset.
900 return false;
901 }
902 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
903 bitmap->reset();
904 return false;
905 }
906 return true;
907}
908
reed96472de2014-12-10 09:53:42 -0800909bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000910 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000911 if (!device) {
912 return false;
913 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000914 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800915
reed96472de2014-12-10 09:53:42 -0800916 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
917 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000918 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000919 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000920
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000921 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800922 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000923}
924
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000925bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700926 SkAutoPixmapUnlock unlocker;
927 if (bitmap.requestLock(&unlocker)) {
928 const SkPixmap& pm = unlocker.pixmap();
929 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000930 }
931 return false;
932}
933
934bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
935 int x, int y) {
936 switch (origInfo.colorType()) {
937 case kUnknown_SkColorType:
938 case kIndex_8_SkColorType:
939 return false;
940 default:
941 break;
942 }
halcanary96fcdcc2015-08-27 07:41:13 -0700943 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000944 return false;
945 }
946
947 const SkISize size = this->getBaseLayerSize();
948 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
949 if (!target.intersect(0, 0, size.width(), size.height())) {
950 return false;
951 }
952
953 SkBaseDevice* device = this->getDevice();
954 if (!device) {
955 return false;
956 }
957
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000958 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700959 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000960
961 // if x or y are negative, then we have to adjust pixels
962 if (x > 0) {
963 x = 0;
964 }
965 if (y > 0) {
966 y = 0;
967 }
968 // here x,y are either 0 or negative
969 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
970
reed4af35f32014-06-27 17:47:49 -0700971 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700972 const bool completeOverwrite = info.dimensions() == size;
973 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700974
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000975 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000976 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000977}
reed@google.com51df9e32010-12-23 19:29:18 +0000978
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979//////////////////////////////////////////////////////////////////////////////
980
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981void SkCanvas::updateDeviceCMCache() {
982 if (fDeviceCMDirty) {
983 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700984 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000985 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000986
halcanary96fcdcc2015-08-27 07:41:13 -0700987 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700988 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000990 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000991 do {
reedde6c5312016-09-02 12:10:07 -0700992 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700993 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994 }
995 fDeviceCMDirty = false;
996 }
997}
998
reed@android.com8a1c16f2008-12-17 15:59:43 +0000999///////////////////////////////////////////////////////////////////////////////
1000
reed2ff1fce2014-12-11 07:07:37 -08001001void SkCanvas::checkForDeferredSave() {
1002 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -08001003 this->doSave();
1004 }
1005}
1006
reedf0090cb2014-11-26 08:55:51 -08001007int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -08001008#ifdef SK_DEBUG
1009 int count = 0;
1010 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1011 for (;;) {
1012 const MCRec* rec = (const MCRec*)iter.next();
1013 if (!rec) {
1014 break;
1015 }
1016 count += 1 + rec->fDeferredSaveCount;
1017 }
1018 SkASSERT(count == fSaveCount);
1019#endif
1020 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001021}
1022
1023int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001024 fSaveCount += 1;
1025 fMCRec->fDeferredSaveCount += 1;
1026 return this->getSaveCount() - 1; // return our prev value
1027}
1028
1029void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001030 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001031
1032 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1033 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001034 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001035}
1036
1037void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001038 if (fMCRec->fDeferredSaveCount > 0) {
1039 SkASSERT(fSaveCount > 1);
1040 fSaveCount -= 1;
1041 fMCRec->fDeferredSaveCount -= 1;
1042 } else {
1043 // check for underflow
1044 if (fMCStack.count() > 1) {
1045 this->willRestore();
1046 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001047 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001048 this->internalRestore();
1049 this->didRestore();
1050 }
reedf0090cb2014-11-26 08:55:51 -08001051 }
1052}
1053
1054void SkCanvas::restoreToCount(int count) {
1055 // sanity check
1056 if (count < 1) {
1057 count = 1;
1058 }
mtkleinf0f14112014-12-12 08:46:25 -08001059
reedf0090cb2014-11-26 08:55:51 -08001060 int n = this->getSaveCount() - count;
1061 for (int i = 0; i < n; ++i) {
1062 this->restore();
1063 }
1064}
1065
reed2ff1fce2014-12-11 07:07:37 -08001066void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001068 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001069 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001070
reed687fa1c2015-04-07 08:00:56 -07001071 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072}
1073
reed4960eee2015-12-18 07:09:18 -08001074bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001075 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001076}
1077
reed4960eee2015-12-18 07:09:18 -08001078bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001079 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001080 SkIRect clipBounds;
1081 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001082 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001083 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001084
reed96e657d2015-03-10 17:30:07 -07001085 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1086
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001087 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001088 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001089 if (bounds && !imageFilter->canComputeFastBounds()) {
1090 bounds = nullptr;
1091 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001092 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001093 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001094 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001096
reed96e657d2015-03-10 17:30:07 -07001097 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098 r.roundOut(&ir);
1099 // early exit if the layer's bounds are clipped out
1100 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001101 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001102 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001103 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001104 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001105 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106 }
1107 } else { // no user bounds, so just use the clip
1108 ir = clipBounds;
1109 }
reed180aec42015-03-11 10:39:04 -07001110 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111
reed4960eee2015-12-18 07:09:18 -08001112 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001113 // Simplify the current clips since they will be applied properly during restore()
Mike Reedc1f77742016-12-09 09:00:50 -05001114 fClipStack->clipDevRect(ir, kReplace_SkClipOp);
reed180aec42015-03-11 10:39:04 -07001115 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001116 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001117 }
1118
1119 if (intersection) {
1120 *intersection = ir;
1121 }
1122 return true;
1123}
1124
reed4960eee2015-12-18 07:09:18 -08001125
reed4960eee2015-12-18 07:09:18 -08001126int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1127 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001128}
1129
reed70ee31b2015-12-10 13:44:45 -08001130int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001131 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1132}
1133
1134int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1135 SaveLayerRec rec(origRec);
1136 if (gIgnoreSaveLayerBounds) {
1137 rec.fBounds = nullptr;
1138 }
1139 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1140 fSaveCount += 1;
1141 this->internalSaveLayer(rec, strategy);
1142 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001143}
1144
reeda2217ef2016-07-20 06:04:34 -07001145void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1146 SkBaseDevice* dst, const SkMatrix& ctm,
1147 const SkClipStack* clipStack) {
1148 SkDraw draw;
1149 SkRasterClip rc;
1150 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1151 if (!dst->accessPixels(&draw.fDst)) {
1152 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001153 }
reeda2217ef2016-07-20 06:04:34 -07001154 draw.fMatrix = &SkMatrix::I();
1155 draw.fRC = &rc;
1156 draw.fClipStack = clipStack;
1157 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001158
1159 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001160 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001161
1162 int x = src->getOrigin().x() - dst->getOrigin().x();
1163 int y = src->getOrigin().y() - dst->getOrigin().y();
1164 auto special = src->snapSpecial();
1165 if (special) {
1166 dst->drawSpecial(draw, special.get(), x, y, p);
1167 }
robertphillips7354a4b2015-12-16 05:08:27 -08001168}
reed70ee31b2015-12-10 13:44:45 -08001169
reed129ed1c2016-02-22 06:42:31 -08001170static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1171 const SkPaint* paint) {
1172 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1173 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001174 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001175 const bool hasImageFilter = paint && paint->getImageFilter();
1176
1177 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1178 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1179 // force to L32
1180 return SkImageInfo::MakeN32(w, h, alphaType);
1181 } else {
1182 // keep the same characteristics as the prev
brianosman52ede1d2016-06-20 08:25:02 -07001183 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace()));
reed129ed1c2016-02-22 06:42:31 -08001184 }
1185}
1186
reed4960eee2015-12-18 07:09:18 -08001187void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1188 const SkRect* bounds = rec.fBounds;
1189 const SkPaint* paint = rec.fPaint;
1190 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1191
reed8c30a812016-04-20 16:36:51 -07001192 SkLazyPaint lazyP;
1193 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1194 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001195 SkMatrix remainder;
1196 SkSize scale;
1197 /*
1198 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1199 * but they do handle scaling. To accommodate this, we do the following:
1200 *
1201 * 1. Stash off the current CTM
1202 * 2. Decompose the CTM into SCALE and REMAINDER
1203 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1204 * contains the REMAINDER
1205 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1206 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1207 * of the original imagefilter, and draw that (via drawSprite)
1208 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1209 *
1210 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1211 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1212 */
reed96a04f32016-04-25 09:25:15 -07001213 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001214 stashedMatrix.decomposeScale(&scale, &remainder))
1215 {
1216 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1217 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1218 SkPaint* p = lazyP.set(*paint);
1219 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1220 SkFilterQuality::kLow_SkFilterQuality,
1221 sk_ref_sp(imageFilter)));
1222 imageFilter = p->getImageFilter();
1223 paint = p;
1224 }
reed8c30a812016-04-20 16:36:51 -07001225
junov@chromium.orga907ac32012-02-24 21:54:07 +00001226 // do this before we create the layer. We don't call the public save() since
1227 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001228 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001229
1230 fDeviceCMDirty = true;
1231
1232 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001233 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001234 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001235 }
1236
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001237 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1238 // the clipRectBounds() call above?
1239 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001240 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001241 }
1242
reed4960eee2015-12-18 07:09:18 -08001243 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001244 SkPixelGeometry geo = fProps.pixelGeometry();
1245 if (paint) {
reed76033be2015-03-14 10:54:31 -07001246 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001247 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001248 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001249 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001250 }
1251 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001252
robertphillips5139e502016-07-19 05:10:40 -07001253 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001254 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001255 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001256 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001257 }
reedb2db8982014-11-13 12:41:02 -08001258
robertphillips5139e502016-07-19 05:10:40 -07001259 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001260 paint);
1261
Hal Canary704cd322016-11-07 14:13:52 -05001262 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001263 {
reed70ee31b2015-12-10 13:44:45 -08001264 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001265 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001266 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001267 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001268 preserveLCDText,
1269 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001270 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1271 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001272 return;
reed61f501f2015-04-29 08:34:00 -07001273 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001274 }
robertphillips5139e502016-07-19 05:10:40 -07001275 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001276
Hal Canary704cd322016-11-07 14:13:52 -05001277 DeviceCM* layer =
1278 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001279
1280 layer->fNext = fMCRec->fTopLayer;
1281 fMCRec->fLayer = layer;
1282 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001283
1284 if (rec.fBackdrop) {
Hal Canary704cd322016-11-07 14:13:52 -05001285 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(),
reeda2217ef2016-07-20 06:04:34 -07001286 fMCRec->fMatrix, this->getClipStack());
1287 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288}
1289
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001290int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001291 if (0xFF == alpha) {
1292 return this->saveLayer(bounds, nullptr);
1293 } else {
1294 SkPaint tmpPaint;
1295 tmpPaint.setAlpha(alpha);
1296 return this->saveLayer(bounds, &tmpPaint);
1297 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001298}
1299
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300void SkCanvas::internalRestore() {
1301 SkASSERT(fMCStack.count() != 0);
1302
1303 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001304
reed687fa1c2015-04-07 08:00:56 -07001305 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001306
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001307 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308 DeviceCM* layer = fMCRec->fLayer; // may be null
1309 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001310 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311
1312 // now do the normal restore()
1313 fMCRec->~MCRec(); // balanced in save()
1314 fMCStack.pop_back();
1315 fMCRec = (MCRec*)fMCStack.back();
1316
1317 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1318 since if we're being recorded, we don't want to record this (the
1319 recorder will have already recorded the restore).
1320 */
bsalomon49f085d2014-09-05 13:34:00 -07001321 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001323 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001324 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001325 // restore what we smashed in internalSaveLayer
1326 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001327 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001329 delete layer;
reedb679ca82015-04-07 04:40:48 -07001330 } else {
1331 // we're at the root
reeda499f902015-05-01 09:34:31 -07001332 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001333 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001334 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001336 }
msarettfbfa2582016-08-12 08:29:08 -07001337
1338 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001339 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001340 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1341 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342}
1343
reede8f30622016-03-23 18:59:25 -07001344sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001345 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001346 props = &fProps;
1347 }
1348 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001349}
1350
reede8f30622016-03-23 18:59:25 -07001351sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001352 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001353 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001354}
1355
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001356SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001357 return this->onImageInfo();
1358}
1359
1360SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001361 SkBaseDevice* dev = this->getDevice();
1362 if (dev) {
1363 return dev->imageInfo();
1364 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001365 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001366 }
1367}
1368
brianosman898235c2016-04-06 07:38:23 -07001369bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001370 return this->onGetProps(props);
1371}
1372
1373bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001374 SkBaseDevice* dev = this->getDevice();
1375 if (dev) {
1376 if (props) {
1377 *props = fProps;
1378 }
1379 return true;
1380 } else {
1381 return false;
1382 }
1383}
1384
reed6ceeebd2016-03-09 14:26:26 -08001385bool SkCanvas::peekPixels(SkPixmap* pmap) {
1386 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001387}
1388
reed884e97c2015-05-26 11:31:54 -07001389bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001390 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001391 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001392}
1393
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001394void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001395 SkPixmap pmap;
1396 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001397 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001398 }
1399 if (info) {
1400 *info = pmap.info();
1401 }
1402 if (rowBytes) {
1403 *rowBytes = pmap.rowBytes();
1404 }
1405 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001406 *origin = this->getTopDevice(false)->getOrigin();
1407 }
reed884e97c2015-05-26 11:31:54 -07001408 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001409}
1410
reed884e97c2015-05-26 11:31:54 -07001411bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001412 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001413 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001414}
1415
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001417
reed7503d602016-07-15 14:23:29 -07001418void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001419 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001420 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001421 paint = &tmp;
1422 }
reed@google.com4b226022011-01-11 18:32:13 +00001423
reed@google.com8926b162012-03-23 15:36:36 +00001424 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001425
reed@android.com8a1c16f2008-12-17 15:59:43 +00001426 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001427 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001428 paint = &looper.paint();
1429 SkImageFilter* filter = paint->getImageFilter();
1430 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001431 if (filter) {
1432 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1433 if (specialImage) {
1434 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1435 }
reed@google.com76dd2772012-01-05 21:15:07 +00001436 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001437 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001438 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001439 }
reeda2217ef2016-07-20 06:04:34 -07001440
reed@google.com4e2b3d32011-04-07 14:18:59 +00001441 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442}
1443
reed32704672015-12-16 08:27:10 -08001444/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001445
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001446void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001447 if (dx || dy) {
1448 this->checkForDeferredSave();
1449 fDeviceCMDirty = true;
1450 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001451
reedfe69b502016-09-12 06:31:48 -07001452 // Translate shouldn't affect the is-scale-translateness of the matrix.
1453 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001454
reedfe69b502016-09-12 06:31:48 -07001455 this->didTranslate(dx,dy);
1456 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001457}
1458
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001459void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001460 SkMatrix m;
1461 m.setScale(sx, sy);
1462 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001463}
1464
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001465void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001466 SkMatrix m;
1467 m.setRotate(degrees);
1468 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001469}
1470
bungeman7438bfc2016-07-12 15:01:19 -07001471void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1472 SkMatrix m;
1473 m.setRotate(degrees, px, py);
1474 this->concat(m);
1475}
1476
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001477void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001478 SkMatrix m;
1479 m.setSkew(sx, sy);
1480 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001481}
1482
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001483void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001484 if (matrix.isIdentity()) {
1485 return;
1486 }
1487
reed2ff1fce2014-12-11 07:07:37 -08001488 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001489 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001490 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001491 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001492 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001493}
1494
reed8c30a812016-04-20 16:36:51 -07001495void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001496 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001497 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001498 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001499}
1500
1501void SkCanvas::setMatrix(const SkMatrix& matrix) {
1502 this->checkForDeferredSave();
1503 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001504 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001505}
1506
reed@android.com8a1c16f2008-12-17 15:59:43 +00001507void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001508 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001509}
1510
vjiaoblack95302da2016-07-21 10:25:54 -07001511#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001512void SkCanvas::translateZ(SkScalar z) {
1513 this->checkForDeferredSave();
1514 this->fMCRec->fCurDrawDepth += z;
1515 this->didTranslateZ(z);
1516}
1517
1518SkScalar SkCanvas::getZ() const {
1519 return this->fMCRec->fCurDrawDepth;
1520}
1521
vjiaoblack95302da2016-07-21 10:25:54 -07001522void SkCanvas::setLights(sk_sp<SkLights> lights) {
1523 this->fLights = lights;
1524}
1525
1526sk_sp<SkLights> SkCanvas::getLights() const {
1527 return this->fLights;
1528}
1529#endif
1530
reed@android.com8a1c16f2008-12-17 15:59:43 +00001531//////////////////////////////////////////////////////////////////////////////
1532
Mike Reedc1f77742016-12-09 09:00:50 -05001533void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001534 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001535 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1536 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001537}
1538
Mike Reedc1f77742016-12-09 09:00:50 -05001539void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001540 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reedc64eff52015-11-21 12:39:45 -08001541 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001542 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1543 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1544 isAA);
reedc64eff52015-11-21 12:39:45 -08001545 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001546 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001547}
1548
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001549void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1550 fClipRestrictionRect = rect;
1551 fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
1552 if (!fClipRestrictionRect.isEmpty()) {
1553 this->checkForDeferredSave();
1554 AutoValidateClip avc(this);
1555 fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
1556 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
1557 fDeviceCMDirty = true;
1558 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1559 }
1560}
1561
Mike Reedc1f77742016-12-09 09:00:50 -05001562void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001563 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001564 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001565 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001566 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1567 } else {
1568 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001569 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001570}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001571
Mike Reedc1f77742016-12-09 09:00:50 -05001572void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001573 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001574
Brian Salomona3b45d42016-10-03 11:36:16 -04001575 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001576
Brian Salomona3b45d42016-10-03 11:36:16 -04001577 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1578 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1579 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1580 isAA);
1581 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1582 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001583}
1584
Mike Reedc1f77742016-12-09 09:00:50 -05001585void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001586 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001587 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001588
1589 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1590 SkRect r;
1591 if (path.isRect(&r)) {
1592 this->onClipRect(r, op, edgeStyle);
1593 return;
1594 }
1595 SkRRect rrect;
1596 if (path.isOval(&r)) {
1597 rrect.setOval(r);
1598 this->onClipRRect(rrect, op, edgeStyle);
1599 return;
1600 }
1601 if (path.isRRect(&rrect)) {
1602 this->onClipRRect(rrect, op, edgeStyle);
1603 return;
1604 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001605 }
robertphillips39f05382015-11-24 09:30:12 -08001606
1607 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001608}
1609
Mike Reedc1f77742016-12-09 09:00:50 -05001610void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001611 AutoValidateClip avc(this);
1612
reed@android.com8a1c16f2008-12-17 15:59:43 +00001613 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001614 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001615
Brian Salomona3b45d42016-10-03 11:36:16 -04001616 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001617
Brian Salomona3b45d42016-10-03 11:36:16 -04001618 const SkPath* rasterClipPath = &path;
1619 const SkMatrix* matrix = &fMCRec->fMatrix;
1620 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001621 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001622 isAA = getClipStack()->asPath(&tempPath);
1623 rasterClipPath = &tempPath;
1624 matrix = &SkMatrix::I();
Mike Reedc1f77742016-12-09 09:00:50 -05001625 op = kReplace_SkClipOp;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001626 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001627 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1628 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001629 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001630}
1631
Mike Reedc1f77742016-12-09 09:00:50 -05001632void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001633 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001634 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001635}
1636
Mike Reedc1f77742016-12-09 09:00:50 -05001637void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001638 AutoValidateClip avc(this);
1639
reed@android.com8a1c16f2008-12-17 15:59:43 +00001640 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001641
reed@google.com5c3d1472011-02-22 19:12:23 +00001642 // todo: signal fClipStack that we have a region, and therefore (I guess)
1643 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001644 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001645
reed73603f32016-09-20 08:42:38 -07001646 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001647 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001648}
1649
reed@google.com819c9212011-02-23 18:56:55 +00001650#ifdef SK_DEBUG
1651void SkCanvas::validateClip() const {
1652 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001653 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001654 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001655 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001656 return;
1657 }
1658
reed@google.com819c9212011-02-23 18:56:55 +00001659 SkIRect ir;
1660 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001661 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001662
reed687fa1c2015-04-07 08:00:56 -07001663 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001664 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001665 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001666 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001667 case SkClipStack::Element::kRect_Type:
1668 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001669 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001670 break;
1671 case SkClipStack::Element::kEmpty_Type:
1672 tmpClip.setEmpty();
1673 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001674 default: {
1675 SkPath path;
1676 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001677 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1678 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001679 break;
1680 }
reed@google.com819c9212011-02-23 18:56:55 +00001681 }
1682 }
reed@google.com819c9212011-02-23 18:56:55 +00001683}
1684#endif
1685
reed@google.com90c07ea2012-04-13 13:50:27 +00001686void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001687 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001688 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001689
halcanary96fcdcc2015-08-27 07:41:13 -07001690 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001691 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001692 }
1693}
1694
reed@google.com5c3d1472011-02-22 19:12:23 +00001695///////////////////////////////////////////////////////////////////////////////
1696
reed@google.com754de5f2014-02-24 19:38:20 +00001697bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001698 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001699}
1700
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001701bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001702 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001703}
1704
msarettfbfa2582016-08-12 08:29:08 -07001705static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1706#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1707 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1708 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1709 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1710 return 0xF != _mm_movemask_ps(mask);
1711#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1712 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1713 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1714 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1715 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1716#else
1717 SkRect devRectAsRect;
1718 SkRect devClipAsRect;
1719 devRect.store(&devRectAsRect.fLeft);
1720 devClip.store(&devClipAsRect.fLeft);
1721 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1722#endif
1723}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001724
msarettfbfa2582016-08-12 08:29:08 -07001725// It's important for this function to not be inlined. Otherwise the compiler will share code
1726// between the fast path and the slow path, resulting in two slow paths.
1727static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1728 const SkMatrix& matrix) {
1729 SkRect deviceRect;
1730 matrix.mapRect(&deviceRect, src);
1731 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1732}
1733
1734bool SkCanvas::quickReject(const SkRect& src) const {
1735#ifdef SK_DEBUG
1736 // Verify that fDeviceClipBounds are set properly.
1737 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001738 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001739 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001740 } else {
msarettfbfa2582016-08-12 08:29:08 -07001741 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001742 }
msarettfbfa2582016-08-12 08:29:08 -07001743
msarett9637ea92016-08-18 14:03:30 -07001744 // Verify that fIsScaleTranslate is set properly.
1745 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001746#endif
1747
msarett9637ea92016-08-18 14:03:30 -07001748 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001749 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1750 }
1751
1752 // We inline the implementation of mapScaleTranslate() for the fast path.
1753 float sx = fMCRec->fMatrix.getScaleX();
1754 float sy = fMCRec->fMatrix.getScaleY();
1755 float tx = fMCRec->fMatrix.getTranslateX();
1756 float ty = fMCRec->fMatrix.getTranslateY();
1757 Sk4f scale(sx, sy, sx, sy);
1758 Sk4f trans(tx, ty, tx, ty);
1759
1760 // Apply matrix.
1761 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1762
1763 // Make sure left < right, top < bottom.
1764 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1765 Sk4f min = Sk4f::Min(ltrb, rblt);
1766 Sk4f max = Sk4f::Max(ltrb, rblt);
1767 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1768 // ARM this sequence generates the fastest (a single instruction).
1769 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1770
1771 // Check if the device rect is NaN or outside the clip.
1772 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001773}
1774
reed@google.com3b3e8952012-08-16 20:53:31 +00001775bool SkCanvas::quickReject(const SkPath& path) const {
1776 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001777}
1778
reed@google.com3b3e8952012-08-16 20:53:31 +00001779bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001780 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001781 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001782 return false;
1783 }
1784
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001785 SkMatrix inverse;
1786 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001787 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001788 if (bounds) {
1789 bounds->setEmpty();
1790 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001791 return false;
1792 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001793
bsalomon49f085d2014-09-05 13:34:00 -07001794 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001795 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001796 // adjust it outwards in case we are antialiasing
1797 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001798
reed@google.com8f4d2302013-12-17 16:44:46 +00001799 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1800 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001801 inverse.mapRect(bounds, r);
1802 }
1803 return true;
1804}
1805
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001806bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001807 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001808 if (clip.isEmpty()) {
1809 if (bounds) {
1810 bounds->setEmpty();
1811 }
1812 return false;
1813 }
1814
bsalomon49f085d2014-09-05 13:34:00 -07001815 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001816 *bounds = clip.getBounds();
1817 }
1818 return true;
1819}
1820
reed@android.com8a1c16f2008-12-17 15:59:43 +00001821const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001822 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001823}
1824
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001825const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001826 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001827}
1828
Brian Osman11052242016-10-27 14:47:55 -04001829GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001830 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001831 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001832}
1833
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001834GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001835 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001836 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001837}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001838
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001839void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1840 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001841 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001842 if (outer.isEmpty()) {
1843 return;
1844 }
1845 if (inner.isEmpty()) {
1846 this->drawRRect(outer, paint);
1847 return;
1848 }
1849
1850 // We don't have this method (yet), but technically this is what we should
1851 // be able to assert...
1852 // SkASSERT(outer.contains(inner));
1853 //
1854 // For now at least check for containment of bounds
1855 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1856
1857 this->onDrawDRRect(outer, inner, paint);
1858}
1859
reed41af9662015-01-05 07:49:08 -08001860// These need to stop being virtual -- clients need to override the onDraw... versions
1861
1862void SkCanvas::drawPaint(const SkPaint& paint) {
1863 this->onDrawPaint(paint);
1864}
1865
1866void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1867 this->onDrawRect(r, paint);
1868}
1869
msarettdca352e2016-08-26 06:37:45 -07001870void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1871 if (region.isEmpty()) {
1872 return;
1873 }
1874
1875 if (region.isRect()) {
1876 return this->drawIRect(region.getBounds(), paint);
1877 }
1878
1879 this->onDrawRegion(region, paint);
1880}
1881
reed41af9662015-01-05 07:49:08 -08001882void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1883 this->onDrawOval(r, paint);
1884}
1885
1886void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1887 this->onDrawRRect(rrect, paint);
1888}
1889
1890void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1891 this->onDrawPoints(mode, count, pts, paint);
1892}
1893
1894void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001895 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001896 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Mike Reedfaba3712016-11-03 14:45:31 -04001897 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, bmode,
reed41af9662015-01-05 07:49:08 -08001898 indices, indexCount, paint);
1899}
1900
1901void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1902 this->onDrawPath(path, paint);
1903}
1904
reeda85d4d02015-05-06 12:56:48 -07001905void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001906 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001907 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001908}
1909
reede47829b2015-08-06 10:02:53 -07001910void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1911 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001912 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001913 if (dst.isEmpty() || src.isEmpty()) {
1914 return;
1915 }
1916 this->onDrawImageRect(image, &src, dst, paint, constraint);
1917}
reed41af9662015-01-05 07:49:08 -08001918
reed84984ef2015-07-17 07:09:43 -07001919void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1920 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001921 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001922 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001923}
1924
reede47829b2015-08-06 10:02:53 -07001925void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1926 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001927 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001928 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1929 constraint);
1930}
reede47829b2015-08-06 10:02:53 -07001931
reed4c21dc52015-06-25 12:32:03 -07001932void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1933 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001934 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001935 if (dst.isEmpty()) {
1936 return;
1937 }
msarett552bca92016-08-03 06:53:26 -07001938 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1939 this->onDrawImageNine(image, center, dst, paint);
1940 } else {
reede47829b2015-08-06 10:02:53 -07001941 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001942 }
reed4c21dc52015-06-25 12:32:03 -07001943}
1944
msarett16882062016-08-16 09:31:08 -07001945void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1946 const SkPaint* paint) {
1947 RETURN_ON_NULL(image);
1948 if (dst.isEmpty()) {
1949 return;
1950 }
msarett71df2d72016-09-30 12:41:42 -07001951
1952 SkIRect bounds;
1953 Lattice latticePlusBounds = lattice;
1954 if (!latticePlusBounds.fBounds) {
1955 bounds = SkIRect::MakeWH(image->width(), image->height());
1956 latticePlusBounds.fBounds = &bounds;
1957 }
1958
1959 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1960 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001961 } else {
1962 this->drawImageRect(image, dst, paint);
1963 }
1964}
1965
reed41af9662015-01-05 07:49:08 -08001966void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001967 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001968 return;
1969 }
reed41af9662015-01-05 07:49:08 -08001970 this->onDrawBitmap(bitmap, dx, dy, paint);
1971}
1972
reede47829b2015-08-06 10:02:53 -07001973void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001974 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001975 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001976 return;
1977 }
reede47829b2015-08-06 10:02:53 -07001978 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001979}
1980
reed84984ef2015-07-17 07:09:43 -07001981void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1982 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001983 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001984}
1985
reede47829b2015-08-06 10:02:53 -07001986void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1987 SrcRectConstraint constraint) {
1988 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1989 constraint);
1990}
reede47829b2015-08-06 10:02:53 -07001991
reed41af9662015-01-05 07:49:08 -08001992void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1993 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001994 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001995 return;
1996 }
msarett552bca92016-08-03 06:53:26 -07001997 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1998 this->onDrawBitmapNine(bitmap, center, dst, paint);
1999 } else {
reeda5517e22015-07-14 10:54:12 -07002000 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002001 }
reed41af9662015-01-05 07:49:08 -08002002}
2003
msarettc573a402016-08-02 08:05:56 -07002004void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2005 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002006 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002007 return;
2008 }
msarett71df2d72016-09-30 12:41:42 -07002009
2010 SkIRect bounds;
2011 Lattice latticePlusBounds = lattice;
2012 if (!latticePlusBounds.fBounds) {
2013 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2014 latticePlusBounds.fBounds = &bounds;
2015 }
2016
2017 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2018 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002019 } else {
msarett16882062016-08-16 09:31:08 -07002020 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002021 }
msarettc573a402016-08-02 08:05:56 -07002022}
2023
reed71c3c762015-06-24 10:29:17 -07002024void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002025 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002026 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002027 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002028 if (count <= 0) {
2029 return;
2030 }
2031 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002032 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002033 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002034}
2035
reedf70b5312016-03-04 16:36:20 -08002036void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2037 if (key) {
2038 this->onDrawAnnotation(rect, key, value);
2039 }
2040}
2041
reede47829b2015-08-06 10:02:53 -07002042void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2043 const SkPaint* paint, SrcRectConstraint constraint) {
2044 if (src) {
2045 this->drawImageRect(image, *src, dst, paint, constraint);
2046 } else {
2047 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2048 dst, paint, constraint);
2049 }
2050}
2051void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2052 const SkPaint* paint, SrcRectConstraint constraint) {
2053 if (src) {
2054 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2055 } else {
2056 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2057 dst, paint, constraint);
2058 }
2059}
2060
tomhudsoncb3bd182016-05-18 07:24:16 -07002061void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2062 SkIRect layer_bounds = this->getTopLayerBounds();
2063 if (matrix) {
2064 *matrix = this->getTotalMatrix();
2065 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2066 }
2067 if (clip_bounds) {
2068 this->getClipDeviceBounds(clip_bounds);
2069 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2070 }
2071}
2072
reed@android.com8a1c16f2008-12-17 15:59:43 +00002073//////////////////////////////////////////////////////////////////////////////
2074// These are the virtual drawing methods
2075//////////////////////////////////////////////////////////////////////////////
2076
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002077void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002078 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002079 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2080 }
2081}
2082
reed41af9662015-01-05 07:49:08 -08002083void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002084 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002085 this->internalDrawPaint(paint);
2086}
2087
2088void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002089 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002090
2091 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002092 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093 }
2094
reed@google.com4e2b3d32011-04-07 14:18:59 +00002095 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002096}
2097
reed41af9662015-01-05 07:49:08 -08002098void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2099 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002100 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002101 if ((long)count <= 0) {
2102 return;
2103 }
2104
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002105 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002106 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002107 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002108 // special-case 2 points (common for drawing a single line)
2109 if (2 == count) {
2110 r.set(pts[0], pts[1]);
2111 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002112 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002113 }
senorblanco87e066e2015-10-28 11:23:36 -07002114 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2115 return;
2116 }
2117 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002118 }
reed@google.coma584aed2012-05-16 14:06:02 +00002119
halcanary96fcdcc2015-08-27 07:41:13 -07002120 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002121
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002122 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002123
reed@android.com8a1c16f2008-12-17 15:59:43 +00002124 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002125 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002126 }
reed@google.com4b226022011-01-11 18:32:13 +00002127
reed@google.com4e2b3d32011-04-07 14:18:59 +00002128 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002129}
2130
reed4a167172016-08-18 17:15:25 -07002131static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2132 return ((intptr_t)paint.getImageFilter() |
2133#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2134 (intptr_t)canvas->getDrawFilter() |
2135#endif
2136 (intptr_t)paint.getLooper() ) != 0;
2137}
2138
reed41af9662015-01-05 07:49:08 -08002139void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002140 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002141 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002142 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002143 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002144 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2145 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2146 SkRect tmp(r);
2147 tmp.sort();
2148
senorblanco87e066e2015-10-28 11:23:36 -07002149 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2150 return;
2151 }
2152 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002153 }
reed@google.com4b226022011-01-11 18:32:13 +00002154
reed4a167172016-08-18 17:15:25 -07002155 if (needs_autodrawlooper(this, paint)) {
2156 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002157
reed4a167172016-08-18 17:15:25 -07002158 while (iter.next()) {
2159 iter.fDevice->drawRect(iter, r, looper.paint());
2160 }
2161
2162 LOOPER_END
2163 } else {
2164 this->predrawNotify(bounds, &paint, false);
2165 SkDrawIter iter(this);
2166 while (iter.next()) {
2167 iter.fDevice->drawRect(iter, r, paint);
2168 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002169 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002170}
2171
msarett44df6512016-08-25 13:54:30 -07002172void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2173 SkRect storage;
2174 SkRect regionRect = SkRect::Make(region.getBounds());
2175 const SkRect* bounds = nullptr;
2176 if (paint.canComputeFastBounds()) {
2177 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2178 return;
2179 }
2180 bounds = &regionRect;
2181 }
2182
2183 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2184
2185 while (iter.next()) {
2186 iter.fDevice->drawRegion(iter, region, looper.paint());
2187 }
2188
2189 LOOPER_END
2190}
2191
reed41af9662015-01-05 07:49:08 -08002192void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002193 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002194 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002195 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002196 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002197 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2198 return;
2199 }
2200 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002201 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002202
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002203 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002204
2205 while (iter.next()) {
2206 iter.fDevice->drawOval(iter, oval, looper.paint());
2207 }
2208
2209 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002210}
2211
bsalomonac3aa242016-08-19 11:25:19 -07002212void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2213 SkScalar sweepAngle, bool useCenter,
2214 const SkPaint& paint) {
2215 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2216 const SkRect* bounds = nullptr;
2217 if (paint.canComputeFastBounds()) {
2218 SkRect storage;
2219 // Note we're using the entire oval as the bounds.
2220 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2221 return;
2222 }
2223 bounds = &oval;
2224 }
2225
2226 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2227
2228 while (iter.next()) {
2229 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2230 }
2231
2232 LOOPER_END
2233}
2234
reed41af9662015-01-05 07:49:08 -08002235void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002236 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002237 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002238 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002239 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002240 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2241 return;
2242 }
2243 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002244 }
2245
2246 if (rrect.isRect()) {
2247 // call the non-virtual version
2248 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002249 return;
2250 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002251 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002252 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2253 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002254 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002255
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002256 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002257
2258 while (iter.next()) {
2259 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2260 }
2261
2262 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002263}
2264
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002265void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2266 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002267 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002268 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002269 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002270 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2271 return;
2272 }
2273 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002274 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002275
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002276 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002277
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002278 while (iter.next()) {
2279 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2280 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002281
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002282 LOOPER_END
2283}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002284
reed41af9662015-01-05 07:49:08 -08002285void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002286 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002287 if (!path.isFinite()) {
2288 return;
2289 }
2290
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002291 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002292 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002293 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002294 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002295 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2296 return;
2297 }
2298 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002299 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002300
2301 const SkRect& r = path.getBounds();
2302 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002303 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002304 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002305 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002306 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002307 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002309 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002310
2311 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002312 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002313 }
2314
reed@google.com4e2b3d32011-04-07 14:18:59 +00002315 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002316}
2317
reed262a71b2015-12-05 13:07:27 -08002318bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002319 if (!paint.getImageFilter()) {
2320 return false;
2321 }
2322
2323 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002324 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002325 return false;
2326 }
2327
2328 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2329 // Once we can filter and the filter will return a result larger than itself, we should be
2330 // able to remove this constraint.
2331 // skbug.com/4526
2332 //
2333 SkPoint pt;
2334 ctm.mapXY(x, y, &pt);
2335 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2336 return ir.contains(fMCRec->fRasterClip.getBounds());
2337}
2338
reeda85d4d02015-05-06 12:56:48 -07002339void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002340 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002341 SkRect bounds = SkRect::MakeXYWH(x, y,
2342 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002343 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002344 SkRect tmp = bounds;
2345 if (paint) {
2346 paint->computeFastBounds(tmp, &tmp);
2347 }
2348 if (this->quickReject(tmp)) {
2349 return;
2350 }
reeda85d4d02015-05-06 12:56:48 -07002351 }
halcanary9d524f22016-03-29 09:03:52 -07002352
reeda85d4d02015-05-06 12:56:48 -07002353 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002354 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002355 paint = lazy.init();
2356 }
reed262a71b2015-12-05 13:07:27 -08002357
reeda2217ef2016-07-20 06:04:34 -07002358 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002359 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2360 *paint);
2361 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002362 special = this->getDevice()->makeSpecial(image);
2363 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002364 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002365 }
2366 }
2367
reed262a71b2015-12-05 13:07:27 -08002368 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2369
reeda85d4d02015-05-06 12:56:48 -07002370 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002371 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002372 if (special) {
2373 SkPoint pt;
2374 iter.fMatrix->mapXY(x, y, &pt);
2375 iter.fDevice->drawSpecial(iter, special.get(),
2376 SkScalarRoundToInt(pt.fX),
2377 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002378 } else {
2379 iter.fDevice->drawImage(iter, image, x, y, pnt);
2380 }
reeda85d4d02015-05-06 12:56:48 -07002381 }
halcanary9d524f22016-03-29 09:03:52 -07002382
reeda85d4d02015-05-06 12:56:48 -07002383 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002384}
2385
reed41af9662015-01-05 07:49:08 -08002386void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002387 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002388 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002389 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002390 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002391 if (paint) {
2392 paint->computeFastBounds(dst, &storage);
2393 }
2394 if (this->quickReject(storage)) {
2395 return;
2396 }
reeda85d4d02015-05-06 12:56:48 -07002397 }
2398 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002399 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002400 paint = lazy.init();
2401 }
halcanary9d524f22016-03-29 09:03:52 -07002402
senorblancoc41e7e12015-12-07 12:51:30 -08002403 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002404 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002405
reeda85d4d02015-05-06 12:56:48 -07002406 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002407 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002408 }
halcanary9d524f22016-03-29 09:03:52 -07002409
reeda85d4d02015-05-06 12:56:48 -07002410 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002411}
2412
reed41af9662015-01-05 07:49:08 -08002413void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002414 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002415 SkDEBUGCODE(bitmap.validate();)
2416
reed33366972015-10-08 09:22:02 -07002417 if (bitmap.drawsNothing()) {
2418 return;
2419 }
2420
2421 SkLazyPaint lazy;
2422 if (nullptr == paint) {
2423 paint = lazy.init();
2424 }
2425
2426 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2427
2428 SkRect storage;
2429 const SkRect* bounds = nullptr;
2430 if (paint->canComputeFastBounds()) {
2431 bitmap.getBounds(&storage);
2432 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002433 SkRect tmp = storage;
2434 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2435 return;
2436 }
2437 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002438 }
reed@google.com4b226022011-01-11 18:32:13 +00002439
reeda2217ef2016-07-20 06:04:34 -07002440 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002441 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2442 *paint);
2443 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002444 special = this->getDevice()->makeSpecial(bitmap);
2445 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002446 drawAsSprite = false;
2447 }
2448 }
2449
reed262a71b2015-12-05 13:07:27 -08002450 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002451
2452 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002453 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002454 if (special) {
reed262a71b2015-12-05 13:07:27 -08002455 SkPoint pt;
2456 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002457 iter.fDevice->drawSpecial(iter, special.get(),
2458 SkScalarRoundToInt(pt.fX),
2459 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002460 } else {
2461 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2462 }
reed33366972015-10-08 09:22:02 -07002463 }
msarettfbfa2582016-08-12 08:29:08 -07002464
reed33366972015-10-08 09:22:02 -07002465 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002466}
2467
reed@google.com9987ec32011-09-07 11:57:52 +00002468// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002469void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002470 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002471 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002472 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473 return;
2474 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002475
halcanary96fcdcc2015-08-27 07:41:13 -07002476 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002477 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002478 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2479 return;
2480 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002481 }
reed@google.com3d608122011-11-21 15:16:16 +00002482
reed@google.com33535f32012-09-25 15:37:50 +00002483 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002484 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002485 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002486 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002487
senorblancoc41e7e12015-12-07 12:51:30 -08002488 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002489 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002490
reed@google.com33535f32012-09-25 15:37:50 +00002491 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002492 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002493 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002494
reed@google.com33535f32012-09-25 15:37:50 +00002495 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496}
2497
reed41af9662015-01-05 07:49:08 -08002498void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002499 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002500 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002501 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002502 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002503}
2504
reed4c21dc52015-06-25 12:32:03 -07002505void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2506 const SkPaint* paint) {
2507 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002508
halcanary96fcdcc2015-08-27 07:41:13 -07002509 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002510 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002511 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2512 return;
2513 }
reed@google.com3d608122011-11-21 15:16:16 +00002514 }
halcanary9d524f22016-03-29 09:03:52 -07002515
reed4c21dc52015-06-25 12:32:03 -07002516 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002517 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002518 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002519 }
halcanary9d524f22016-03-29 09:03:52 -07002520
senorblancoc41e7e12015-12-07 12:51:30 -08002521 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002522
reed4c21dc52015-06-25 12:32:03 -07002523 while (iter.next()) {
2524 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002525 }
halcanary9d524f22016-03-29 09:03:52 -07002526
reed4c21dc52015-06-25 12:32:03 -07002527 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002528}
2529
reed41af9662015-01-05 07:49:08 -08002530void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2531 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002532 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002533 SkDEBUGCODE(bitmap.validate();)
2534
halcanary96fcdcc2015-08-27 07:41:13 -07002535 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002536 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002537 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2538 return;
2539 }
reed4c21dc52015-06-25 12:32:03 -07002540 }
halcanary9d524f22016-03-29 09:03:52 -07002541
reed4c21dc52015-06-25 12:32:03 -07002542 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002543 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002544 paint = lazy.init();
2545 }
halcanary9d524f22016-03-29 09:03:52 -07002546
senorblancoc41e7e12015-12-07 12:51:30 -08002547 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002548
reed4c21dc52015-06-25 12:32:03 -07002549 while (iter.next()) {
2550 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2551 }
halcanary9d524f22016-03-29 09:03:52 -07002552
reed4c21dc52015-06-25 12:32:03 -07002553 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002554}
2555
msarett16882062016-08-16 09:31:08 -07002556void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2557 const SkPaint* paint) {
2558 if (nullptr == paint || paint->canComputeFastBounds()) {
2559 SkRect storage;
2560 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2561 return;
2562 }
2563 }
2564
2565 SkLazyPaint lazy;
2566 if (nullptr == paint) {
2567 paint = lazy.init();
2568 }
2569
2570 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2571
2572 while (iter.next()) {
2573 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2574 }
2575
2576 LOOPER_END
2577}
2578
2579void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2580 const SkRect& dst, const SkPaint* paint) {
2581 if (nullptr == paint || paint->canComputeFastBounds()) {
2582 SkRect storage;
2583 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2584 return;
2585 }
2586 }
2587
2588 SkLazyPaint lazy;
2589 if (nullptr == paint) {
2590 paint = lazy.init();
2591 }
2592
2593 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2594
2595 while (iter.next()) {
2596 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2597 }
2598
2599 LOOPER_END
2600}
2601
reed@google.comf67e4cf2011-03-15 20:56:58 +00002602class SkDeviceFilteredPaint {
2603public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002604 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002605 uint32_t filteredFlags = device->filterTextFlags(paint);
2606 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002607 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002608 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002609 fPaint = newPaint;
2610 } else {
2611 fPaint = &paint;
2612 }
2613 }
2614
reed@google.comf67e4cf2011-03-15 20:56:58 +00002615 const SkPaint& paint() const { return *fPaint; }
2616
2617private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002618 const SkPaint* fPaint;
2619 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002620};
2621
bungeman@google.com52c748b2011-08-22 21:30:43 +00002622void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2623 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002624 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002625 draw.fDevice->drawRect(draw, r, paint);
2626 } else {
2627 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002628 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002629 draw.fDevice->drawRect(draw, r, p);
2630 }
2631}
2632
2633void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2634 const char text[], size_t byteLength,
2635 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002636 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002637
2638 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002639 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002640 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002641 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002642 return;
2643 }
2644
2645 SkScalar width = 0;
2646 SkPoint start;
2647
2648 start.set(0, 0); // to avoid warning
2649 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2650 SkPaint::kStrikeThruText_Flag)) {
2651 width = paint.measureText(text, byteLength);
2652
2653 SkScalar offsetX = 0;
2654 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2655 offsetX = SkScalarHalf(width);
2656 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2657 offsetX = width;
2658 }
2659 start.set(x - offsetX, y);
2660 }
2661
2662 if (0 == width) {
2663 return;
2664 }
2665
2666 uint32_t flags = paint.getFlags();
2667
2668 if (flags & (SkPaint::kUnderlineText_Flag |
2669 SkPaint::kStrikeThruText_Flag)) {
2670 SkScalar textSize = paint.getTextSize();
2671 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2672 SkRect r;
2673
2674 r.fLeft = start.fX;
2675 r.fRight = start.fX + width;
2676
2677 if (flags & SkPaint::kUnderlineText_Flag) {
2678 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2679 start.fY);
2680 r.fTop = offset;
2681 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002682 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002683 }
2684 if (flags & SkPaint::kStrikeThruText_Flag) {
2685 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2686 start.fY);
2687 r.fTop = offset;
2688 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002689 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002690 }
2691 }
2692}
2693
reed@google.come0d9ce82014-04-23 04:00:17 +00002694void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2695 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002696 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697
2698 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002699 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002700 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002701 DrawTextDecorations(iter, dfp.paint(),
2702 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002703 }
2704
reed@google.com4e2b3d32011-04-07 14:18:59 +00002705 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002706}
2707
reed@google.come0d9ce82014-04-23 04:00:17 +00002708void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2709 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002710 SkPoint textOffset = SkPoint::Make(0, 0);
2711
halcanary96fcdcc2015-08-27 07:41:13 -07002712 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002713
reed@android.com8a1c16f2008-12-17 15:59:43 +00002714 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002715 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002716 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002717 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002718 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002719
reed@google.com4e2b3d32011-04-07 14:18:59 +00002720 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002721}
2722
reed@google.come0d9ce82014-04-23 04:00:17 +00002723void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2724 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002725
2726 SkPoint textOffset = SkPoint::Make(0, constY);
2727
halcanary96fcdcc2015-08-27 07:41:13 -07002728 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002729
reed@android.com8a1c16f2008-12-17 15:59:43 +00002730 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002731 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002732 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002733 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002734 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002735
reed@google.com4e2b3d32011-04-07 14:18:59 +00002736 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002737}
2738
reed@google.come0d9ce82014-04-23 04:00:17 +00002739void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2740 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002741 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002742
reed@android.com8a1c16f2008-12-17 15:59:43 +00002743 while (iter.next()) {
2744 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002745 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002746 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002747
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002748 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002749}
2750
reed45561a02016-07-07 12:47:17 -07002751void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2752 const SkRect* cullRect, const SkPaint& paint) {
2753 if (cullRect && this->quickReject(*cullRect)) {
2754 return;
2755 }
2756
2757 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2758
2759 while (iter.next()) {
2760 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2761 }
2762
2763 LOOPER_END
2764}
2765
fmalita00d5c2c2014-08-21 08:53:26 -07002766void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2767 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002768
fmalita85d5eb92015-03-04 11:20:12 -08002769 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002770 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002771 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002772 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002773 SkRect tmp;
2774 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2775 return;
2776 }
2777 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002778 }
2779
fmalita024f9962015-03-03 19:08:17 -08002780 // We cannot filter in the looper as we normally do, because the paint is
2781 // incomplete at this point (text-related attributes are embedded within blob run paints).
2782 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002783 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002784
fmalita85d5eb92015-03-04 11:20:12 -08002785 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002786
fmalitaaa1b9122014-08-28 14:32:24 -07002787 while (iter.next()) {
2788 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002789 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002790 }
2791
fmalitaaa1b9122014-08-28 14:32:24 -07002792 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002793
2794 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002795}
2796
reed@google.come0d9ce82014-04-23 04:00:17 +00002797// These will become non-virtual, so they always call the (virtual) onDraw... method
2798void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2799 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002800 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002801 if (byteLength) {
2802 this->onDrawText(text, byteLength, x, y, paint);
2803 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002804}
2805void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2806 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002807 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002808 if (byteLength) {
2809 this->onDrawPosText(text, byteLength, pos, paint);
2810 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002811}
2812void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2813 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002814 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002815 if (byteLength) {
2816 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2817 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002818}
2819void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2820 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002821 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002822 if (byteLength) {
2823 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2824 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002825}
reed45561a02016-07-07 12:47:17 -07002826void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2827 const SkRect* cullRect, const SkPaint& paint) {
2828 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2829 if (byteLength) {
2830 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2831 }
2832}
fmalita00d5c2c2014-08-21 08:53:26 -07002833void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2834 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002835 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002836 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002837 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002838}
reed@google.come0d9ce82014-04-23 04:00:17 +00002839
reed41af9662015-01-05 07:49:08 -08002840void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2841 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002842 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002843 const uint16_t indices[], int indexCount,
2844 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002845 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002846 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002847
reed@android.com8a1c16f2008-12-17 15:59:43 +00002848 while (iter.next()) {
2849 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002850 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002851 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002852 }
reed@google.com4b226022011-01-11 18:32:13 +00002853
reed@google.com4e2b3d32011-04-07 14:18:59 +00002854 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002855}
2856
dandovb3c9d1c2014-08-12 08:34:29 -07002857void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002858 const SkPoint texCoords[4], SkBlendMode bmode,
2859 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002860 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002861 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002862 return;
2863 }
mtklein6cfa73a2014-08-13 13:33:49 -07002864
Mike Reedfaba3712016-11-03 14:45:31 -04002865 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002866}
2867
2868void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002869 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002870 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002871 // Since a patch is always within the convex hull of the control points, we discard it when its
2872 // bounding rectangle is completely outside the current clip.
2873 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002874 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002875 if (this->quickReject(bounds)) {
2876 return;
2877 }
mtklein6cfa73a2014-08-13 13:33:49 -07002878
halcanary96fcdcc2015-08-27 07:41:13 -07002879 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002880
dandovecfff212014-08-04 10:02:00 -07002881 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002882 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002883 }
mtklein6cfa73a2014-08-13 13:33:49 -07002884
dandovecfff212014-08-04 10:02:00 -07002885 LOOPER_END
2886}
2887
reeda8db7282015-07-07 10:22:31 -07002888void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002889 RETURN_ON_NULL(dr);
2890 if (x || y) {
2891 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2892 this->onDrawDrawable(dr, &matrix);
2893 } else {
2894 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002895 }
2896}
2897
reeda8db7282015-07-07 10:22:31 -07002898void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002899 RETURN_ON_NULL(dr);
2900 if (matrix && matrix->isIdentity()) {
2901 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002902 }
reede3b38ce2016-01-08 09:18:44 -08002903 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002904}
2905
2906void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002907 // drawable bounds are no longer reliable (e.g. android displaylist)
2908 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002909 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002910}
2911
reed71c3c762015-06-24 10:29:17 -07002912void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002913 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002914 const SkRect* cull, const SkPaint* paint) {
2915 if (cull && this->quickReject(*cull)) {
2916 return;
2917 }
2918
2919 SkPaint pnt;
2920 if (paint) {
2921 pnt = *paint;
2922 }
halcanary9d524f22016-03-29 09:03:52 -07002923
halcanary96fcdcc2015-08-27 07:41:13 -07002924 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002925 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002926 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002927 }
2928 LOOPER_END
2929}
2930
reedf70b5312016-03-04 16:36:20 -08002931void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2932 SkASSERT(key);
2933
2934 SkPaint paint;
2935 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2936 while (iter.next()) {
2937 iter.fDevice->drawAnnotation(iter, rect, key, value);
2938 }
2939 LOOPER_END
2940}
2941
reed@android.com8a1c16f2008-12-17 15:59:43 +00002942//////////////////////////////////////////////////////////////////////////////
2943// These methods are NOT virtual, and therefore must call back into virtual
2944// methods, rather than actually drawing themselves.
2945//////////////////////////////////////////////////////////////////////////////
2946
reed374772b2016-10-05 17:33:02 -07002947void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002948 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002949 SkPaint paint;
2950
2951 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002952 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002953 this->drawPaint(paint);
2954}
2955
reed374772b2016-10-05 17:33:02 -07002956void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002957 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002958 SkPaint paint;
2959
2960 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002961 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002962 this->drawPaint(paint);
2963}
2964
2965void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002966 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002967 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002968
reed@android.com8a1c16f2008-12-17 15:59:43 +00002969 pt.set(x, y);
2970 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2971}
2972
2973void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002974 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002975 SkPoint pt;
2976 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002977
reed@android.com8a1c16f2008-12-17 15:59:43 +00002978 pt.set(x, y);
2979 paint.setColor(color);
2980 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2981}
2982
2983void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2984 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002985 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002986 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002987
reed@android.com8a1c16f2008-12-17 15:59:43 +00002988 pts[0].set(x0, y0);
2989 pts[1].set(x1, y1);
2990 this->drawPoints(kLines_PointMode, 2, pts, paint);
2991}
2992
2993void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2994 SkScalar right, SkScalar bottom,
2995 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002996 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002997 SkRect r;
2998
2999 r.set(left, top, right, bottom);
3000 this->drawRect(r, paint);
3001}
3002
3003void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3004 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003005 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003006 if (radius < 0) {
3007 radius = 0;
3008 }
3009
3010 SkRect r;
3011 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003012 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003013}
3014
3015void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3016 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003017 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003018 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003019 SkRRect rrect;
3020 rrect.setRectXY(r, rx, ry);
3021 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003022 } else {
3023 this->drawRect(r, paint);
3024 }
3025}
3026
reed@android.com8a1c16f2008-12-17 15:59:43 +00003027void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3028 SkScalar sweepAngle, bool useCenter,
3029 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003030 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003031 if (oval.isEmpty() || !sweepAngle) {
3032 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003033 }
bsalomon21af9ca2016-08-25 12:29:23 -07003034 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003035}
3036
3037void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3038 const SkPath& path, SkScalar hOffset,
3039 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003040 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003041 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003042
reed@android.com8a1c16f2008-12-17 15:59:43 +00003043 matrix.setTranslate(hOffset, vOffset);
3044 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3045}
3046
reed@android.comf76bacf2009-05-13 14:00:33 +00003047///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003048
3049/**
3050 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3051 * against the playback cost of recursing into the subpicture to get at its actual ops.
3052 *
3053 * For now we pick a conservatively small value, though measurement (and other heuristics like
3054 * the type of ops contained) may justify changing this value.
3055 */
3056#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003057
reedd5fa1a42014-08-09 11:08:05 -07003058void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003059 RETURN_ON_NULL(picture);
3060
reed1c2c4412015-04-30 13:09:24 -07003061 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003062 if (matrix && matrix->isIdentity()) {
3063 matrix = nullptr;
3064 }
3065 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3066 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3067 picture->playback(this);
3068 } else {
3069 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003070 }
3071}
robertphillips9b14f262014-06-04 05:40:44 -07003072
reedd5fa1a42014-08-09 11:08:05 -07003073void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3074 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003075 if (!paint || paint->canComputeFastBounds()) {
3076 SkRect bounds = picture->cullRect();
3077 if (paint) {
3078 paint->computeFastBounds(bounds, &bounds);
3079 }
3080 if (matrix) {
3081 matrix->mapRect(&bounds);
3082 }
3083 if (this->quickReject(bounds)) {
3084 return;
3085 }
3086 }
3087
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003088 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003089 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003090}
3091
vjiaoblack95302da2016-07-21 10:25:54 -07003092#ifdef SK_EXPERIMENTAL_SHADOWING
3093void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3094 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003095 const SkPaint* paint,
3096 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003097 RETURN_ON_NULL(picture);
3098
3099 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3100
vjiaoblacke6f5d562016-08-25 06:30:23 -07003101 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003102}
3103
3104void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3105 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003106 const SkPaint* paint,
3107 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003108 if (!paint || paint->canComputeFastBounds()) {
3109 SkRect bounds = picture->cullRect();
3110 if (paint) {
3111 paint->computeFastBounds(bounds, &bounds);
3112 }
3113 if (matrix) {
3114 matrix->mapRect(&bounds);
3115 }
3116 if (this->quickReject(bounds)) {
3117 return;
3118 }
3119 }
3120
3121 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3122
vjiaoblacke6f5d562016-08-25 06:30:23 -07003123 sk_sp<SkImage> povDepthMap;
3124 sk_sp<SkImage> diffuseMap;
3125
vjiaoblack904527d2016-08-09 09:32:09 -07003126 // povDepthMap
3127 {
3128 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003129 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3130 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003131 sk_sp<SkLights> povLight = builder.finish();
3132
3133 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3134 picture->cullRect().height(),
3135 kBGRA_8888_SkColorType,
3136 kOpaque_SkAlphaType);
3137
3138 // Create a new surface (that matches the backend of canvas)
3139 // to create the povDepthMap
3140 sk_sp<SkSurface> surf(this->makeSurface(info));
3141
3142 // Wrap another SPFCanvas around the surface
3143 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3144 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3145
3146 // set the depth map canvas to have the light as the user's POV
3147 depthMapCanvas->setLights(std::move(povLight));
3148
3149 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003150 povDepthMap = surf->makeImageSnapshot();
3151 }
3152
3153 // diffuseMap
3154 {
3155 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3156 picture->cullRect().height(),
3157 kBGRA_8888_SkColorType,
3158 kOpaque_SkAlphaType);
3159
3160 sk_sp<SkSurface> surf(this->makeSurface(info));
3161 surf->getCanvas()->drawPicture(picture);
3162
3163 diffuseMap = surf->makeImageSnapshot();
3164 }
vjiaoblack904527d2016-08-09 09:32:09 -07003165
3166 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3167 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003168 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3169 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003170
3171 // TODO: pass the depth to the shader in vertices, or uniforms
3172 // so we don't have to render depth and color separately
3173 for (int i = 0; i < fLights->numLights(); ++i) {
3174 // skip over ambient lights; they don't cast shadows
3175 // lights that have shadow maps do not need updating (because lights are immutable)
3176 sk_sp<SkImage> depthMap;
3177 SkISize shMapSize;
3178
3179 if (fLights->light(i).getShadowMap() != nullptr) {
3180 continue;
3181 }
3182
3183 if (fLights->light(i).isRadial()) {
3184 shMapSize.fHeight = 1;
3185 shMapSize.fWidth = (int) picture->cullRect().width();
3186
3187 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3188 kBGRA_8888_SkColorType,
3189 kOpaque_SkAlphaType);
3190
3191 // Create new surface (that matches the backend of canvas)
3192 // for each shadow map
3193 sk_sp<SkSurface> surf(this->makeSurface(info));
3194
3195 // Wrap another SPFCanvas around the surface
3196 SkCanvas* depthMapCanvas = surf->getCanvas();
3197
3198 SkLights::Builder builder;
3199 builder.add(fLights->light(i));
3200 sk_sp<SkLights> curLight = builder.finish();
3201
3202 sk_sp<SkShader> shadowMapShader;
3203 shadowMapShader = SkRadialShadowMapShader::Make(
3204 povDepthShader, curLight,
3205 (int) picture->cullRect().width(),
3206 (int) picture->cullRect().height());
3207
3208 SkPaint shadowMapPaint;
3209 shadowMapPaint.setShader(std::move(shadowMapShader));
3210
3211 depthMapCanvas->setLights(curLight);
3212
3213 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3214 diffuseMap->height()),
3215 shadowMapPaint);
3216
3217 depthMap = surf->makeImageSnapshot();
3218
3219 } else {
3220 // TODO: compute the correct size of the depth map from the light properties
3221 // TODO: maybe add a kDepth_8_SkColorType
3222 // TODO: find actual max depth of picture
3223 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3224 fLights->light(i), 255,
3225 (int) picture->cullRect().width(),
3226 (int) picture->cullRect().height());
3227
3228 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3229 kBGRA_8888_SkColorType,
3230 kOpaque_SkAlphaType);
3231
3232 // Create a new surface (that matches the backend of canvas)
3233 // for each shadow map
3234 sk_sp<SkSurface> surf(this->makeSurface(info));
3235
3236 // Wrap another SPFCanvas around the surface
3237 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3238 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3239 depthMapCanvas->setShadowParams(params);
3240
3241 // set the depth map canvas to have the light we're drawing.
3242 SkLights::Builder builder;
3243 builder.add(fLights->light(i));
3244 sk_sp<SkLights> curLight = builder.finish();
3245 depthMapCanvas->setLights(std::move(curLight));
3246
3247 depthMapCanvas->drawPicture(picture);
3248 depthMap = surf->makeImageSnapshot();
3249 }
3250
3251 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3252 fLights->light(i).setShadowMap(std::move(depthMap));
3253 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3254 // we blur the variance map
3255 SkPaint blurPaint;
3256 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3257 params.fShadowRadius, nullptr));
3258
3259 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3260 kBGRA_8888_SkColorType,
3261 kOpaque_SkAlphaType);
3262
3263 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3264
3265 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3266
3267 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3268 }
3269 }
3270
3271 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003272 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3273 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003274 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003275 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003276 diffuseMap->height(),
3277 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003278
3279 shadowPaint.setShader(shadowShader);
3280
3281 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003282}
3283#endif
3284
reed@android.com8a1c16f2008-12-17 15:59:43 +00003285///////////////////////////////////////////////////////////////////////////////
3286///////////////////////////////////////////////////////////////////////////////
3287
reed3aafe112016-08-18 12:45:34 -07003288SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003289 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003290
3291 SkASSERT(canvas);
3292
reed3aafe112016-08-18 12:45:34 -07003293 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003294 fDone = !fImpl->next();
3295}
3296
3297SkCanvas::LayerIter::~LayerIter() {
3298 fImpl->~SkDrawIter();
3299}
3300
3301void SkCanvas::LayerIter::next() {
3302 fDone = !fImpl->next();
3303}
3304
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003305SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003306 return fImpl->getDevice();
3307}
3308
3309const SkMatrix& SkCanvas::LayerIter::matrix() const {
3310 return fImpl->getMatrix();
3311}
3312
3313const SkPaint& SkCanvas::LayerIter::paint() const {
3314 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003315 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003316 paint = &fDefaultPaint;
3317 }
3318 return *paint;
3319}
3320
reed1e7f5e72016-04-27 07:49:17 -07003321const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003322int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3323int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003324
3325///////////////////////////////////////////////////////////////////////////////
3326
fmalitac3b589a2014-06-05 12:40:07 -07003327SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003328
3329///////////////////////////////////////////////////////////////////////////////
3330
3331static bool supported_for_raster_canvas(const SkImageInfo& info) {
3332 switch (info.alphaType()) {
3333 case kPremul_SkAlphaType:
3334 case kOpaque_SkAlphaType:
3335 break;
3336 default:
3337 return false;
3338 }
3339
3340 switch (info.colorType()) {
3341 case kAlpha_8_SkColorType:
3342 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003343 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003344 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003345 break;
3346 default:
3347 return false;
3348 }
3349
3350 return true;
3351}
3352
Mike Reed5df49342016-11-12 08:06:55 -06003353std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3354 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003355 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003356 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003357 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003358
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003359 SkBitmap bitmap;
3360 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003361 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003362 }
Mike Reed5df49342016-11-12 08:06:55 -06003363 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003364}
reedd5fa1a42014-08-09 11:08:05 -07003365
3366///////////////////////////////////////////////////////////////////////////////
3367
3368SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003369 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003370 : fCanvas(canvas)
3371 , fSaveCount(canvas->getSaveCount())
3372{
bsalomon49f085d2014-09-05 13:34:00 -07003373 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003374 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003375 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003376 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003377 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003378 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003379 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003380 canvas->save();
3381 }
mtklein6cfa73a2014-08-13 13:33:49 -07003382
bsalomon49f085d2014-09-05 13:34:00 -07003383 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003384 canvas->concat(*matrix);
3385 }
3386}
3387
3388SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3389 fCanvas->restoreToCount(fSaveCount);
3390}
reede8f30622016-03-23 18:59:25 -07003391
Florin Malitaee424ac2016-12-01 12:47:59 -05003392///////////////////////////////////////////////////////////////////////////////
3393
3394SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3395 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3396
Florin Malita439ace92016-12-02 12:05:41 -05003397SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3398 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3399
Florin Malitaee424ac2016-12-01 12:47:59 -05003400SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3401 (void)this->INHERITED::getSaveLayerStrategy(rec);
3402 return kNoLayer_SaveLayerStrategy;
3403}
3404
3405///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003406
reed73603f32016-09-20 08:42:38 -07003407static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3408static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3409static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3410static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3411static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3412static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003413
3414///////////////////////////////////////////////////////////////////////////////////////////////////
3415
3416SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3417 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3418 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3419 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3420 SkIPoint origin = dev->getOrigin();
3421 SkMatrix ctm = this->getTotalMatrix();
3422 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3423
3424 SkIRect clip = fMCRec->fRasterClip.getBounds();
3425 clip.offset(-origin.x(), -origin.y());
3426 if (clip.intersect(0, 0, dev->width(), dev->height())) {
3427 clip.setEmpty();
3428 }
3429
3430 fAllocator->updateHandle(handle, ctm, clip);
3431 return handle;
3432 }
3433 return nullptr;
3434}
3435
3436static bool install(SkBitmap* bm, const SkImageInfo& info,
3437 const SkRasterHandleAllocator::Rec& rec) {
3438 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3439 rec.fReleaseProc, rec.fReleaseCtx);
3440}
3441
3442SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3443 SkBitmap* bm) {
3444 SkRasterHandleAllocator::Rec rec;
3445 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3446 return nullptr;
3447 }
3448 return rec.fHandle;
3449}
3450
3451std::unique_ptr<SkCanvas>
3452SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3453 const SkImageInfo& info, const Rec* rec) {
3454 if (!alloc || !supported_for_raster_canvas(info)) {
3455 return nullptr;
3456 }
3457
3458 SkBitmap bm;
3459 Handle hndl;
3460
3461 if (rec) {
3462 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3463 } else {
3464 hndl = alloc->allocBitmap(info, &bm);
3465 }
3466 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3467}