blob: 0375ab738dda900041977a4ca0f969b932738b6e [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
Mike Reed986480a2017-01-13 22:43:16 +00008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070017#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080018#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070019#include "SkImageFilter.h"
20#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070021#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060022#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050025#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070026#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070027#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070028#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000029#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070030#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000031#include "SkRasterClip.h"
Mike Reed356f7c22017-01-10 11:58:39 -050032#include "SkRasterHandleAllocator.h"
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 Reed693fdbd2017-01-12 10:13:40 -0500488 tmp.setImageFilter(fPaint->refImageFilter());
reed374772b2016-10-05 17:33:02 -0700489 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700490 SkRect storage;
491 if (rawBounds) {
492 // Make rawBounds include all paint outsets except for those due to image filters.
493 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
494 }
reedbfd5f172016-01-07 11:28:08 -0800495 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700496 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700497 fTempLayerForImageFilter = true;
498 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000499 }
500
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000501 if (SkDrawLooper* looper = paint.getLooper()) {
herbbf6d80a2016-11-15 06:26:56 -0800502 fLooperContext = fLooperContextAllocator.createWithIniter(
503 looper->contextSize(),
504 [&](void* buffer) {
505 return looper->createContext(canvas, buffer);
506 });
reed@google.com129ec222012-05-15 13:24:09 +0000507 fIsSimple = false;
508 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700509 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000510 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700511 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000512 }
513 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000514
reed@android.com8a1c16f2008-12-17 15:59:43 +0000515 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700516 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000517 fCanvas->internalRestore();
518 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000519 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000520 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000521
reed@google.com4e2b3d32011-04-07 14:18:59 +0000522 const SkPaint& paint() const {
523 SkASSERT(fPaint);
524 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000526
reed@google.com129ec222012-05-15 13:24:09 +0000527 bool next(SkDrawFilter::Type drawType) {
528 if (fDone) {
529 return false;
530 } else if (fIsSimple) {
531 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000532 return !fPaint->nothingToDraw();
533 } else {
534 return this->doNext(drawType);
535 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000536 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000537
reed@android.com8a1c16f2008-12-17 15:59:43 +0000538private:
reeddbc3cef2015-04-29 12:18:57 -0700539 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
540 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000541 SkCanvas* fCanvas;
542 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000543 SkDrawFilter* fFilter;
544 const SkPaint* fPaint;
545 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700546 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000547 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000548 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000549 SkDrawLooper::Context* fLooperContext;
550 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000551
552 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553};
554
reed@google.com129ec222012-05-15 13:24:09 +0000555bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700556 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000557 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700558 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000559
reeddbc3cef2015-04-29 12:18:57 -0700560 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
561 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000562
reed5c476fb2015-04-20 08:04:21 -0700563 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700564 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700565 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000566 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000567
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000568 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000569 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000570 return false;
571 }
572 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000573 if (!fFilter->filter(paint, drawType)) {
574 fDone = true;
575 return false;
576 }
halcanary96fcdcc2015-08-27 07:41:13 -0700577 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000578 // no looper means we only draw once
579 fDone = true;
580 }
581 }
582 fPaint = paint;
583
584 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000585 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000586 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000587 }
588
589 // call this after any possible paint modifiers
590 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700591 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000592 return false;
593 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000594 return true;
595}
596
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597////////// macros to place around the internal draw calls //////////////////
598
reed3aafe112016-08-18 12:45:34 -0700599#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
600 this->predrawNotify(); \
601 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
602 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800603 SkDrawIter iter(this);
604
605
reed@google.com8926b162012-03-23 15:36:36 +0000606#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000607 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700608 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000609 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000610 SkDrawIter iter(this);
611
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000612#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000613 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700614 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000615 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000616 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000617
reedc83a2972015-07-16 07:40:45 -0700618#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
619 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700620 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700621 while (looper.next(type)) { \
622 SkDrawIter iter(this);
623
reed@google.com4e2b3d32011-04-07 14:18:59 +0000624#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625
626////////////////////////////////////////////////////////////////////////////
627
msarettfbfa2582016-08-12 08:29:08 -0700628static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
629 if (bounds.isEmpty()) {
630 return SkRect::MakeEmpty();
631 }
632
633 // Expand bounds out by 1 in case we are anti-aliasing. We store the
634 // bounds as floats to enable a faster quick reject implementation.
635 SkRect dst;
636 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
637 return dst;
638}
639
mtkleinfeaadee2015-04-08 11:25:48 -0700640void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
641 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700642 fClipStack->reset();
643 fMCRec->reset(bounds);
644
645 // We're peering through a lot of structs here. Only at this scope do we
646 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
647 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700648 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700649 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700650}
651
reedd9544982014-09-09 18:46:22 -0700652SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800653 if (device && device->forceConservativeRasterClip()) {
654 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
655 }
656 // Since init() is only called once by our constructors, it is safe to perform this
657 // const-cast.
658 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
659
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000660 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700661 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800662 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700663 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700664#ifdef SK_EXPERIMENTAL_SHADOWING
665 fLights = nullptr;
666#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667
halcanary385fe4d2015-08-26 13:07:48 -0700668 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700669
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700671 new (fMCRec) MCRec(fConservativeRasterClip);
Stan Iliev5f1bb0a2016-12-12 17:39:55 -0500672 fMCRec->fRasterClip.setDeviceClipRestriction(&fClipRestrictionRect);
msarett9637ea92016-08-18 14:03:30 -0700673 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674
reeda499f902015-05-01 09:34:31 -0700675 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
676 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700677 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700678 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700679
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681
halcanary96fcdcc2015-08-27 07:41:13 -0700682 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000683
reedf92c8662014-08-18 08:02:43 -0700684 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700685 // The root device and the canvas should always have the same pixel geometry
686 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700687 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800688 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700689 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700690 }
msarettfbfa2582016-08-12 08:29:08 -0700691
reedf92c8662014-08-18 08:02:43 -0700692 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693}
694
reed@google.comcde92112011-07-06 20:00:52 +0000695SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000696 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700697 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800698 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000699{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000700 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000701
halcanary96fcdcc2015-08-27 07:41:13 -0700702 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000703}
704
reedd9544982014-09-09 18:46:22 -0700705static SkBitmap make_nopixels(int width, int height) {
706 SkBitmap bitmap;
707 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
708 return bitmap;
709}
710
711class SkNoPixelsBitmapDevice : public SkBitmapDevice {
712public:
robertphillipsfcf78292015-06-19 11:49:52 -0700713 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
714 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800715 {
716 this->setOrigin(bounds.x(), bounds.y());
717 }
reedd9544982014-09-09 18:46:22 -0700718
719private:
piotaixrb5fae932014-09-24 13:03:30 -0700720
reedd9544982014-09-09 18:46:22 -0700721 typedef SkBitmapDevice INHERITED;
722};
723
reed96a857e2015-01-25 10:33:58 -0800724SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000725 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800726 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800727 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000728{
729 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700730
halcanary385fe4d2015-08-26 13:07:48 -0700731 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
732 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700733}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000734
reed78e27682014-11-19 08:04:34 -0800735SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700736 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700737 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800738 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700739{
740 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700741
halcanary385fe4d2015-08-26 13:07:48 -0700742 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700743}
744
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000745SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000746 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700747 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800748 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000749{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700751
reedd9544982014-09-09 18:46:22 -0700752 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753}
754
robertphillipsfcf78292015-06-19 11:49:52 -0700755SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
756 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700757 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800758 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700759{
760 inc_canvas();
761
762 this->init(device, flags);
763}
764
reed4a8126e2014-09-22 07:29:03 -0700765SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700766 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700767 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800768 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700769{
770 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700771
Hal Canary704cd322016-11-07 14:13:52 -0500772 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
773 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700774}
reed29c857d2014-09-21 10:25:07 -0700775
Mike Reed356f7c22017-01-10 11:58:39 -0500776SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
777 SkRasterHandleAllocator::Handle hndl)
reed4a8126e2014-09-22 07:29:03 -0700778 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
779 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
Mike Reed356f7c22017-01-10 11:58:39 -0500780 , fAllocator(std::move(alloc))
reed42b73eb2015-11-20 13:42:42 -0800781 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700782{
783 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700784
Mike Reed356f7c22017-01-10 11:58:39 -0500785 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
Hal Canary704cd322016-11-07 14:13:52 -0500786 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000787}
788
Mike Reed356f7c22017-01-10 11:58:39 -0500789SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
790
reed@android.com8a1c16f2008-12-17 15:59:43 +0000791SkCanvas::~SkCanvas() {
792 // free up the contents of our deque
793 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000794
reed@android.com8a1c16f2008-12-17 15:59:43 +0000795 this->internalRestore(); // restore the last, since we're going away
796
halcanary385fe4d2015-08-26 13:07:48 -0700797 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000798
reed@android.com8a1c16f2008-12-17 15:59:43 +0000799 dec_canvas();
800}
801
fmalita53d9f1c2016-01-25 06:23:54 -0800802#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000803SkDrawFilter* SkCanvas::getDrawFilter() const {
804 return fMCRec->fFilter;
805}
806
807SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700808 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
810 return filter;
811}
fmalita77650002016-01-21 18:47:11 -0800812#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000814SkMetaData& SkCanvas::getMetaData() {
815 // metadata users are rare, so we lazily allocate it. If that changes we
816 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700817 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000818 fMetaData = new SkMetaData;
819 }
820 return *fMetaData;
821}
822
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823///////////////////////////////////////////////////////////////////////////////
824
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000825void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700826 this->onFlush();
827}
828
829void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000830 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000831 if (device) {
832 device->flush();
833 }
834}
835
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000836SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000837 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000838 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
839}
840
senorblancoafc7cce2016-02-02 18:44:15 -0800841SkIRect SkCanvas::getTopLayerBounds() const {
842 SkBaseDevice* d = this->getTopDevice();
843 if (!d) {
844 return SkIRect::MakeEmpty();
845 }
846 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
847}
848
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000849SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000851 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000852 SkASSERT(rec && rec->fLayer);
853 return rec->fLayer->fDevice;
854}
855
Florin Malita0ed3b642017-01-13 16:56:38 +0000856SkBaseDevice* SkCanvas::getTopDevice() const {
reed@google.com9266fed2011-03-30 00:18:03 +0000857 return fMCRec->fTopLayer->fDevice;
858}
859
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000860bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700861 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000862 return false;
863 }
864
865 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700866 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700867 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000868 return false;
869 }
870 weAllocated = true;
871 }
872
reedcf01e312015-05-23 19:14:51 -0700873 SkAutoPixmapUnlock unlocker;
874 if (bitmap->requestLock(&unlocker)) {
875 const SkPixmap& pm = unlocker.pixmap();
876 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
877 return true;
878 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000879 }
880
881 if (weAllocated) {
Hal Canary1b3387b2016-12-12 13:48:12 -0500882 bitmap->setPixelRef(nullptr, 0, 0);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000883 }
884 return false;
885}
reed@google.com51df9e32010-12-23 19:29:18 +0000886
bsalomon@google.comc6980972011-11-02 19:57:21 +0000887bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000888 SkIRect r = srcRect;
889 const SkISize size = this->getBaseLayerSize();
890 if (!r.intersect(0, 0, size.width(), size.height())) {
891 bitmap->reset();
892 return false;
893 }
894
reed84825042014-09-02 12:50:45 -0700895 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000896 // bitmap will already be reset.
897 return false;
898 }
899 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
900 bitmap->reset();
901 return false;
902 }
903 return true;
904}
905
reed96472de2014-12-10 09:53:42 -0800906bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000907 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000908 if (!device) {
909 return false;
910 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000911 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800912
reed96472de2014-12-10 09:53:42 -0800913 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
914 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000915 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000916 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000917
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000918 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800919 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000920}
921
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000922bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700923 SkAutoPixmapUnlock unlocker;
924 if (bitmap.requestLock(&unlocker)) {
925 const SkPixmap& pm = unlocker.pixmap();
926 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000927 }
928 return false;
929}
930
931bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
932 int x, int y) {
933 switch (origInfo.colorType()) {
934 case kUnknown_SkColorType:
935 case kIndex_8_SkColorType:
936 return false;
937 default:
938 break;
939 }
halcanary96fcdcc2015-08-27 07:41:13 -0700940 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000941 return false;
942 }
943
944 const SkISize size = this->getBaseLayerSize();
945 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
946 if (!target.intersect(0, 0, size.width(), size.height())) {
947 return false;
948 }
949
950 SkBaseDevice* device = this->getDevice();
951 if (!device) {
952 return false;
953 }
954
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000955 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700956 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000957
958 // if x or y are negative, then we have to adjust pixels
959 if (x > 0) {
960 x = 0;
961 }
962 if (y > 0) {
963 y = 0;
964 }
965 // here x,y are either 0 or negative
966 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
967
reed4af35f32014-06-27 17:47:49 -0700968 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700969 const bool completeOverwrite = info.dimensions() == size;
970 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700971
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000972 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000973 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000974}
reed@google.com51df9e32010-12-23 19:29:18 +0000975
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976//////////////////////////////////////////////////////////////////////////////
977
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978void SkCanvas::updateDeviceCMCache() {
979 if (fDeviceCMDirty) {
980 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700981 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000983
halcanary96fcdcc2015-08-27 07:41:13 -0700984 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700985 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000987 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988 do {
reedde6c5312016-09-02 12:10:07 -0700989 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700990 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000991 }
992 fDeviceCMDirty = false;
993 }
994}
995
reed@android.com8a1c16f2008-12-17 15:59:43 +0000996///////////////////////////////////////////////////////////////////////////////
997
reed2ff1fce2014-12-11 07:07:37 -0800998void SkCanvas::checkForDeferredSave() {
999 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -08001000 this->doSave();
1001 }
1002}
1003
reedf0090cb2014-11-26 08:55:51 -08001004int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -08001005#ifdef SK_DEBUG
1006 int count = 0;
1007 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1008 for (;;) {
1009 const MCRec* rec = (const MCRec*)iter.next();
1010 if (!rec) {
1011 break;
1012 }
1013 count += 1 + rec->fDeferredSaveCount;
1014 }
1015 SkASSERT(count == fSaveCount);
1016#endif
1017 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001018}
1019
1020int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001021 fSaveCount += 1;
1022 fMCRec->fDeferredSaveCount += 1;
1023 return this->getSaveCount() - 1; // return our prev value
1024}
1025
1026void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001027 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001028
1029 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1030 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001031 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001032}
1033
1034void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001035 if (fMCRec->fDeferredSaveCount > 0) {
1036 SkASSERT(fSaveCount > 1);
1037 fSaveCount -= 1;
1038 fMCRec->fDeferredSaveCount -= 1;
1039 } else {
1040 // check for underflow
1041 if (fMCStack.count() > 1) {
1042 this->willRestore();
1043 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001044 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001045 this->internalRestore();
1046 this->didRestore();
1047 }
reedf0090cb2014-11-26 08:55:51 -08001048 }
1049}
1050
1051void SkCanvas::restoreToCount(int count) {
1052 // sanity check
1053 if (count < 1) {
1054 count = 1;
1055 }
mtkleinf0f14112014-12-12 08:46:25 -08001056
reedf0090cb2014-11-26 08:55:51 -08001057 int n = this->getSaveCount() - count;
1058 for (int i = 0; i < n; ++i) {
1059 this->restore();
1060 }
1061}
1062
reed2ff1fce2014-12-11 07:07:37 -08001063void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001065 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001066 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001067
reed687fa1c2015-04-07 08:00:56 -07001068 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001069}
1070
reed4960eee2015-12-18 07:09:18 -08001071bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001072 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001073}
1074
reed4960eee2015-12-18 07:09:18 -08001075bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001076 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001077 SkIRect clipBounds;
1078 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001079 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001080 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001081
reed96e657d2015-03-10 17:30:07 -07001082 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1083
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001084 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001085 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001086 if (bounds && !imageFilter->canComputeFastBounds()) {
1087 bounds = nullptr;
1088 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001089 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001090 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001091 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001092 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001093
reed96e657d2015-03-10 17:30:07 -07001094 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095 r.roundOut(&ir);
1096 // early exit if the layer's bounds are clipped out
1097 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001098 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001099 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001100 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001101 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001102 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001103 }
1104 } else { // no user bounds, so just use the clip
1105 ir = clipBounds;
1106 }
reed180aec42015-03-11 10:39:04 -07001107 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001108
reed4960eee2015-12-18 07:09:18 -08001109 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001110 // Simplify the current clips since they will be applied properly during restore()
Mike Reedc1f77742016-12-09 09:00:50 -05001111 fClipStack->clipDevRect(ir, kReplace_SkClipOp);
reed180aec42015-03-11 10:39:04 -07001112 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001113 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001114 }
1115
1116 if (intersection) {
1117 *intersection = ir;
1118 }
1119 return true;
1120}
1121
reed4960eee2015-12-18 07:09:18 -08001122
reed4960eee2015-12-18 07:09:18 -08001123int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1124 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001125}
1126
reed70ee31b2015-12-10 13:44:45 -08001127int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001128 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1129}
1130
1131int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1132 SaveLayerRec rec(origRec);
1133 if (gIgnoreSaveLayerBounds) {
1134 rec.fBounds = nullptr;
1135 }
1136 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1137 fSaveCount += 1;
1138 this->internalSaveLayer(rec, strategy);
1139 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001140}
1141
reeda2217ef2016-07-20 06:04:34 -07001142void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1143 SkBaseDevice* dst, const SkMatrix& ctm,
1144 const SkClipStack* clipStack) {
1145 SkDraw draw;
1146 SkRasterClip rc;
1147 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1148 if (!dst->accessPixels(&draw.fDst)) {
1149 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001150 }
reeda2217ef2016-07-20 06:04:34 -07001151 draw.fMatrix = &SkMatrix::I();
1152 draw.fRC = &rc;
1153 draw.fClipStack = clipStack;
1154 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001155
1156 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001157 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001158
1159 int x = src->getOrigin().x() - dst->getOrigin().x();
1160 int y = src->getOrigin().y() - dst->getOrigin().y();
1161 auto special = src->snapSpecial();
1162 if (special) {
1163 dst->drawSpecial(draw, special.get(), x, y, p);
1164 }
robertphillips7354a4b2015-12-16 05:08:27 -08001165}
reed70ee31b2015-12-10 13:44:45 -08001166
reed129ed1c2016-02-22 06:42:31 -08001167static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1168 const SkPaint* paint) {
1169 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1170 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001171 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001172 const bool hasImageFilter = paint && paint->getImageFilter();
1173
1174 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1175 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1176 // force to L32
1177 return SkImageInfo::MakeN32(w, h, alphaType);
1178 } else {
1179 // keep the same characteristics as the prev
Mike Reed693fdbd2017-01-12 10:13:40 -05001180 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.refColorSpace());
reed129ed1c2016-02-22 06:42:31 -08001181 }
1182}
1183
reed4960eee2015-12-18 07:09:18 -08001184void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1185 const SkRect* bounds = rec.fBounds;
1186 const SkPaint* paint = rec.fPaint;
1187 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1188
reed8c30a812016-04-20 16:36:51 -07001189 SkLazyPaint lazyP;
1190 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1191 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001192 SkMatrix remainder;
1193 SkSize scale;
1194 /*
1195 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1196 * but they do handle scaling. To accommodate this, we do the following:
1197 *
1198 * 1. Stash off the current CTM
1199 * 2. Decompose the CTM into SCALE and REMAINDER
1200 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1201 * contains the REMAINDER
1202 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1203 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1204 * of the original imagefilter, and draw that (via drawSprite)
1205 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1206 *
1207 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1208 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1209 */
reed96a04f32016-04-25 09:25:15 -07001210 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001211 stashedMatrix.decomposeScale(&scale, &remainder))
1212 {
1213 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1214 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1215 SkPaint* p = lazyP.set(*paint);
1216 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1217 SkFilterQuality::kLow_SkFilterQuality,
1218 sk_ref_sp(imageFilter)));
1219 imageFilter = p->getImageFilter();
1220 paint = p;
1221 }
reed8c30a812016-04-20 16:36:51 -07001222
junov@chromium.orga907ac32012-02-24 21:54:07 +00001223 // do this before we create the layer. We don't call the public save() since
1224 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001225 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001226
1227 fDeviceCMDirty = true;
1228
1229 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001230 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001231 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001232 }
1233
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001234 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1235 // the clipRectBounds() call above?
1236 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001237 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001238 }
1239
reed4960eee2015-12-18 07:09:18 -08001240 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001241 SkPixelGeometry geo = fProps.pixelGeometry();
1242 if (paint) {
reed76033be2015-03-14 10:54:31 -07001243 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001244 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001245 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001246 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001247 }
1248 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249
robertphillips5139e502016-07-19 05:10:40 -07001250 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001251 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001252 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001253 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001254 }
reedb2db8982014-11-13 12:41:02 -08001255
robertphillips5139e502016-07-19 05:10:40 -07001256 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001257 paint);
1258
Hal Canary704cd322016-11-07 14:13:52 -05001259 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001260 {
reed70ee31b2015-12-10 13:44:45 -08001261 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001262 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001263 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001264 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
Mike Reed356f7c22017-01-10 11:58:39 -05001265 preserveLCDText,
1266 fAllocator.get());
robertphillips5139e502016-07-19 05:10:40 -07001267 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1268 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001269 return;
reed61f501f2015-04-29 08:34:00 -07001270 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001271 }
robertphillips5139e502016-07-19 05:10:40 -07001272 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001273
Hal Canary704cd322016-11-07 14:13:52 -05001274 DeviceCM* layer =
1275 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001276
1277 layer->fNext = fMCRec->fTopLayer;
1278 fMCRec->fLayer = layer;
1279 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001280
1281 if (rec.fBackdrop) {
Hal Canary704cd322016-11-07 14:13:52 -05001282 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(),
reeda2217ef2016-07-20 06:04:34 -07001283 fMCRec->fMatrix, this->getClipStack());
1284 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285}
1286
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001287int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001288 if (0xFF == alpha) {
1289 return this->saveLayer(bounds, nullptr);
1290 } else {
1291 SkPaint tmpPaint;
1292 tmpPaint.setAlpha(alpha);
1293 return this->saveLayer(bounds, &tmpPaint);
1294 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001295}
1296
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297void SkCanvas::internalRestore() {
1298 SkASSERT(fMCStack.count() != 0);
1299
1300 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301
reed687fa1c2015-04-07 08:00:56 -07001302 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001303
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001304 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 DeviceCM* layer = fMCRec->fLayer; // may be null
1306 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001307 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308
1309 // now do the normal restore()
1310 fMCRec->~MCRec(); // balanced in save()
1311 fMCStack.pop_back();
1312 fMCRec = (MCRec*)fMCStack.back();
1313
1314 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1315 since if we're being recorded, we don't want to record this (the
1316 recorder will have already recorded the restore).
1317 */
bsalomon49f085d2014-09-05 13:34:00 -07001318 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001320 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001321 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001322 // restore what we smashed in internalSaveLayer
1323 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001324 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001325 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001326 delete layer;
reedb679ca82015-04-07 04:40:48 -07001327 } else {
1328 // we're at the root
reeda499f902015-05-01 09:34:31 -07001329 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001330 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001331 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001333 }
msarettfbfa2582016-08-12 08:29:08 -07001334
1335 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001336 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001337 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1338 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339}
1340
reede8f30622016-03-23 18:59:25 -07001341sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001342 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001343 props = &fProps;
1344 }
1345 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001346}
1347
reede8f30622016-03-23 18:59:25 -07001348sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001349 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001350 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001351}
1352
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001353SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001354 return this->onImageInfo();
1355}
1356
1357SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001358 SkBaseDevice* dev = this->getDevice();
1359 if (dev) {
1360 return dev->imageInfo();
1361 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001362 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001363 }
1364}
1365
brianosman898235c2016-04-06 07:38:23 -07001366bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001367 return this->onGetProps(props);
1368}
1369
1370bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001371 SkBaseDevice* dev = this->getDevice();
1372 if (dev) {
1373 if (props) {
1374 *props = fProps;
1375 }
1376 return true;
1377 } else {
1378 return false;
1379 }
1380}
1381
reed6ceeebd2016-03-09 14:26:26 -08001382bool SkCanvas::peekPixels(SkPixmap* pmap) {
1383 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001384}
1385
reed884e97c2015-05-26 11:31:54 -07001386bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001387 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001388 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001389}
1390
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001391void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001392 SkPixmap pmap;
1393 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001394 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001395 }
1396 if (info) {
1397 *info = pmap.info();
1398 }
1399 if (rowBytes) {
1400 *rowBytes = pmap.rowBytes();
1401 }
1402 if (origin) {
Florin Malita0ed3b642017-01-13 16:56:38 +00001403 *origin = this->getTopDevice()->getOrigin();
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001404 }
reed884e97c2015-05-26 11:31:54 -07001405 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001406}
1407
reed884e97c2015-05-26 11:31:54 -07001408bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001409 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001410 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001411}
1412
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414
reed7503d602016-07-15 14:23:29 -07001415void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001417 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418 paint = &tmp;
1419 }
reed@google.com4b226022011-01-11 18:32:13 +00001420
reed@google.com8926b162012-03-23 15:36:36 +00001421 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001422
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001424 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001425 paint = &looper.paint();
1426 SkImageFilter* filter = paint->getImageFilter();
1427 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001428 if (filter) {
1429 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1430 if (specialImage) {
1431 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1432 }
reed@google.com76dd2772012-01-05 21:15:07 +00001433 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001434 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001435 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001436 }
reeda2217ef2016-07-20 06:04:34 -07001437
reed@google.com4e2b3d32011-04-07 14:18:59 +00001438 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001439}
1440
reed32704672015-12-16 08:27:10 -08001441/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001442
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001443void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001444 if (dx || dy) {
1445 this->checkForDeferredSave();
1446 fDeviceCMDirty = true;
1447 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001448
reedfe69b502016-09-12 06:31:48 -07001449 // Translate shouldn't affect the is-scale-translateness of the matrix.
1450 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001451
reedfe69b502016-09-12 06:31:48 -07001452 this->didTranslate(dx,dy);
1453 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001454}
1455
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001456void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001457 SkMatrix m;
1458 m.setScale(sx, sy);
1459 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001460}
1461
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001462void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001463 SkMatrix m;
1464 m.setRotate(degrees);
1465 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001466}
1467
bungeman7438bfc2016-07-12 15:01:19 -07001468void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1469 SkMatrix m;
1470 m.setRotate(degrees, px, py);
1471 this->concat(m);
1472}
1473
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001474void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001475 SkMatrix m;
1476 m.setSkew(sx, sy);
1477 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001478}
1479
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001480void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001481 if (matrix.isIdentity()) {
1482 return;
1483 }
1484
reed2ff1fce2014-12-11 07:07:37 -08001485 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001486 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001487 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001488 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001489 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001490}
1491
reed8c30a812016-04-20 16:36:51 -07001492void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001493 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001494 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001495 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001496}
1497
1498void SkCanvas::setMatrix(const SkMatrix& matrix) {
1499 this->checkForDeferredSave();
1500 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001501 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001502}
1503
reed@android.com8a1c16f2008-12-17 15:59:43 +00001504void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001505 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001506}
1507
vjiaoblack95302da2016-07-21 10:25:54 -07001508#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001509void SkCanvas::translateZ(SkScalar z) {
1510 this->checkForDeferredSave();
1511 this->fMCRec->fCurDrawDepth += z;
1512 this->didTranslateZ(z);
1513}
1514
1515SkScalar SkCanvas::getZ() const {
1516 return this->fMCRec->fCurDrawDepth;
1517}
1518
vjiaoblack95302da2016-07-21 10:25:54 -07001519void SkCanvas::setLights(sk_sp<SkLights> lights) {
1520 this->fLights = lights;
1521}
1522
1523sk_sp<SkLights> SkCanvas::getLights() const {
1524 return this->fLights;
1525}
1526#endif
1527
reed@android.com8a1c16f2008-12-17 15:59:43 +00001528//////////////////////////////////////////////////////////////////////////////
1529
Mike Reedc1f77742016-12-09 09:00:50 -05001530void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001531 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001532 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1533 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001534}
1535
Mike Reedc1f77742016-12-09 09:00:50 -05001536void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001537 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reedc64eff52015-11-21 12:39:45 -08001538 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001539 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1540 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1541 isAA);
reedc64eff52015-11-21 12:39:45 -08001542 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001543 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001544}
1545
Stan Iliev5f1bb0a2016-12-12 17:39:55 -05001546void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1547 fClipRestrictionRect = rect;
1548 fClipStack->setDeviceClipRestriction(fClipRestrictionRect);
1549 if (!fClipRestrictionRect.isEmpty()) {
1550 this->checkForDeferredSave();
1551 AutoValidateClip avc(this);
1552 fClipStack->clipDevRect(fClipRestrictionRect, kIntersect_SkClipOp);
1553 fMCRec->fRasterClip.op(fClipRestrictionRect, SkRegion::kIntersect_Op);
1554 fDeviceCMDirty = true;
1555 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1556 }
1557}
1558
Mike Reedc1f77742016-12-09 09:00:50 -05001559void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001560 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001561 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001562 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001563 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1564 } else {
1565 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001566 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001567}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001568
Mike Reedc1f77742016-12-09 09:00:50 -05001569void SkCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001570 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001571
Brian Salomona3b45d42016-10-03 11:36:16 -04001572 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001573
Brian Salomona3b45d42016-10-03 11:36:16 -04001574 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1575 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1576 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1577 isAA);
1578 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1579 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001580}
1581
Mike Reedc1f77742016-12-09 09:00:50 -05001582void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001583 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001584 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001585
1586 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1587 SkRect r;
1588 if (path.isRect(&r)) {
1589 this->onClipRect(r, op, edgeStyle);
1590 return;
1591 }
1592 SkRRect rrect;
1593 if (path.isOval(&r)) {
1594 rrect.setOval(r);
1595 this->onClipRRect(rrect, op, edgeStyle);
1596 return;
1597 }
1598 if (path.isRRect(&rrect)) {
1599 this->onClipRRect(rrect, op, edgeStyle);
1600 return;
1601 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001602 }
robertphillips39f05382015-11-24 09:30:12 -08001603
1604 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001605}
1606
Mike Reedc1f77742016-12-09 09:00:50 -05001607void SkCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001608 AutoValidateClip avc(this);
1609
reed@android.com8a1c16f2008-12-17 15:59:43 +00001610 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001611 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001612
Brian Salomona3b45d42016-10-03 11:36:16 -04001613 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001614
Brian Salomona3b45d42016-10-03 11:36:16 -04001615 const SkPath* rasterClipPath = &path;
1616 const SkMatrix* matrix = &fMCRec->fMatrix;
1617 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001618 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001619 isAA = getClipStack()->asPath(&tempPath);
1620 rasterClipPath = &tempPath;
1621 matrix = &SkMatrix::I();
Mike Reedc1f77742016-12-09 09:00:50 -05001622 op = kReplace_SkClipOp;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001623 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001624 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1625 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001626 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001627}
1628
Mike Reedc1f77742016-12-09 09:00:50 -05001629void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001630 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001631 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001632}
1633
Mike Reedc1f77742016-12-09 09:00:50 -05001634void SkCanvas::onClipRegion(const SkRegion& rgn, SkClipOp op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001635 AutoValidateClip avc(this);
1636
reed@android.com8a1c16f2008-12-17 15:59:43 +00001637 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001638
reed@google.com5c3d1472011-02-22 19:12:23 +00001639 // todo: signal fClipStack that we have a region, and therefore (I guess)
1640 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001641 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001642
reed73603f32016-09-20 08:42:38 -07001643 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001644 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001645}
1646
reed@google.com819c9212011-02-23 18:56:55 +00001647#ifdef SK_DEBUG
1648void SkCanvas::validateClip() const {
1649 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001650 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001651 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001652 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001653 return;
1654 }
1655
reed@google.com819c9212011-02-23 18:56:55 +00001656 SkIRect ir;
1657 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001658 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001659
reed687fa1c2015-04-07 08:00:56 -07001660 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001661 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001662 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001663 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001664 case SkClipStack::Element::kRect_Type:
1665 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001666 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001667 break;
1668 case SkClipStack::Element::kEmpty_Type:
1669 tmpClip.setEmpty();
1670 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001671 default: {
1672 SkPath path;
1673 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001674 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1675 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001676 break;
1677 }
reed@google.com819c9212011-02-23 18:56:55 +00001678 }
1679 }
reed@google.com819c9212011-02-23 18:56:55 +00001680}
1681#endif
1682
reed@google.com90c07ea2012-04-13 13:50:27 +00001683void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001684 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001685 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001686
halcanary96fcdcc2015-08-27 07:41:13 -07001687 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001688 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001689 }
1690}
1691
reed@google.com5c3d1472011-02-22 19:12:23 +00001692///////////////////////////////////////////////////////////////////////////////
1693
reed@google.com754de5f2014-02-24 19:38:20 +00001694bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001695 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001696}
1697
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001698bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001699 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001700}
1701
msarettfbfa2582016-08-12 08:29:08 -07001702static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1703#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1704 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1705 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1706 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1707 return 0xF != _mm_movemask_ps(mask);
1708#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1709 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1710 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1711 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1712 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1713#else
1714 SkRect devRectAsRect;
1715 SkRect devClipAsRect;
1716 devRect.store(&devRectAsRect.fLeft);
1717 devClip.store(&devClipAsRect.fLeft);
1718 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1719#endif
1720}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001721
msarettfbfa2582016-08-12 08:29:08 -07001722// It's important for this function to not be inlined. Otherwise the compiler will share code
1723// between the fast path and the slow path, resulting in two slow paths.
1724static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1725 const SkMatrix& matrix) {
1726 SkRect deviceRect;
1727 matrix.mapRect(&deviceRect, src);
1728 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1729}
1730
1731bool SkCanvas::quickReject(const SkRect& src) const {
1732#ifdef SK_DEBUG
1733 // Verify that fDeviceClipBounds are set properly.
1734 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001735 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001736 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001737 } else {
msarettfbfa2582016-08-12 08:29:08 -07001738 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001739 }
msarettfbfa2582016-08-12 08:29:08 -07001740
msarett9637ea92016-08-18 14:03:30 -07001741 // Verify that fIsScaleTranslate is set properly.
1742 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001743#endif
1744
msarett9637ea92016-08-18 14:03:30 -07001745 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001746 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1747 }
1748
1749 // We inline the implementation of mapScaleTranslate() for the fast path.
1750 float sx = fMCRec->fMatrix.getScaleX();
1751 float sy = fMCRec->fMatrix.getScaleY();
1752 float tx = fMCRec->fMatrix.getTranslateX();
1753 float ty = fMCRec->fMatrix.getTranslateY();
1754 Sk4f scale(sx, sy, sx, sy);
1755 Sk4f trans(tx, ty, tx, ty);
1756
1757 // Apply matrix.
1758 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1759
1760 // Make sure left < right, top < bottom.
1761 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1762 Sk4f min = Sk4f::Min(ltrb, rblt);
1763 Sk4f max = Sk4f::Max(ltrb, rblt);
1764 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1765 // ARM this sequence generates the fastest (a single instruction).
1766 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1767
1768 // Check if the device rect is NaN or outside the clip.
1769 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001770}
1771
reed@google.com3b3e8952012-08-16 20:53:31 +00001772bool SkCanvas::quickReject(const SkPath& path) const {
1773 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001774}
1775
reed@google.com3b3e8952012-08-16 20:53:31 +00001776bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001777 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001778 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001779 return false;
1780 }
1781
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001782 SkMatrix inverse;
1783 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001784 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001785 if (bounds) {
1786 bounds->setEmpty();
1787 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001788 return false;
1789 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001790
bsalomon49f085d2014-09-05 13:34:00 -07001791 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001792 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001793 // adjust it outwards in case we are antialiasing
1794 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001795
reed@google.com8f4d2302013-12-17 16:44:46 +00001796 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1797 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001798 inverse.mapRect(bounds, r);
1799 }
1800 return true;
1801}
1802
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001803bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001804 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001805 if (clip.isEmpty()) {
1806 if (bounds) {
1807 bounds->setEmpty();
1808 }
1809 return false;
1810 }
1811
bsalomon49f085d2014-09-05 13:34:00 -07001812 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001813 *bounds = clip.getBounds();
1814 }
1815 return true;
1816}
1817
reed@android.com8a1c16f2008-12-17 15:59:43 +00001818const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001819 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001820}
1821
Mike Reed3726a4a2017-01-19 11:36:41 -05001822void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1823 // we know that ganesh doesn't track the rgn, so ask for its clipstack
1824 if (this->getGrContext()) {
1825 SkPath path;
1826 this->getClipStack()->asPath(&path);
1827 SkISize size = this->getBaseLayerSize();
1828 rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
1829 } else {
1830 *rgn = fMCRec->fRasterClip.forceGetBW();
1831 }
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001832}
1833
Brian Osman11052242016-10-27 14:47:55 -04001834GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001835 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001836 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001837}
1838
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001839GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001840 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001841 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001842}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001843
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001844void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1845 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001846 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001847 if (outer.isEmpty()) {
1848 return;
1849 }
1850 if (inner.isEmpty()) {
1851 this->drawRRect(outer, paint);
1852 return;
1853 }
1854
1855 // We don't have this method (yet), but technically this is what we should
1856 // be able to assert...
1857 // SkASSERT(outer.contains(inner));
1858 //
1859 // For now at least check for containment of bounds
1860 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1861
1862 this->onDrawDRRect(outer, inner, paint);
1863}
1864
reed41af9662015-01-05 07:49:08 -08001865// These need to stop being virtual -- clients need to override the onDraw... versions
1866
1867void SkCanvas::drawPaint(const SkPaint& paint) {
1868 this->onDrawPaint(paint);
1869}
1870
1871void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1872 this->onDrawRect(r, paint);
1873}
1874
msarettdca352e2016-08-26 06:37:45 -07001875void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1876 if (region.isEmpty()) {
1877 return;
1878 }
1879
1880 if (region.isRect()) {
1881 return this->drawIRect(region.getBounds(), paint);
1882 }
1883
1884 this->onDrawRegion(region, paint);
1885}
1886
reed41af9662015-01-05 07:49:08 -08001887void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1888 this->onDrawOval(r, paint);
1889}
1890
1891void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1892 this->onDrawRRect(rrect, paint);
1893}
1894
1895void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1896 this->onDrawPoints(mode, count, pts, paint);
1897}
1898
1899void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001900 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001901 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Mike Reedfaba3712016-11-03 14:45:31 -04001902 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, bmode,
reed41af9662015-01-05 07:49:08 -08001903 indices, indexCount, paint);
1904}
1905
1906void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1907 this->onDrawPath(path, paint);
1908}
1909
reeda85d4d02015-05-06 12:56:48 -07001910void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001911 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001912 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001913}
1914
reede47829b2015-08-06 10:02:53 -07001915void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1916 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001917 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001918 if (dst.isEmpty() || src.isEmpty()) {
1919 return;
1920 }
1921 this->onDrawImageRect(image, &src, dst, paint, constraint);
1922}
reed41af9662015-01-05 07:49:08 -08001923
reed84984ef2015-07-17 07:09:43 -07001924void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1925 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001926 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001927 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001928}
1929
reede47829b2015-08-06 10:02:53 -07001930void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1931 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001932 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001933 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1934 constraint);
1935}
reede47829b2015-08-06 10:02:53 -07001936
reed4c21dc52015-06-25 12:32:03 -07001937void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1938 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001939 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001940 if (dst.isEmpty()) {
1941 return;
1942 }
msarett552bca92016-08-03 06:53:26 -07001943 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1944 this->onDrawImageNine(image, center, dst, paint);
1945 } else {
reede47829b2015-08-06 10:02:53 -07001946 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001947 }
reed4c21dc52015-06-25 12:32:03 -07001948}
1949
msarett16882062016-08-16 09:31:08 -07001950void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1951 const SkPaint* paint) {
1952 RETURN_ON_NULL(image);
1953 if (dst.isEmpty()) {
1954 return;
1955 }
msarett71df2d72016-09-30 12:41:42 -07001956
1957 SkIRect bounds;
1958 Lattice latticePlusBounds = lattice;
1959 if (!latticePlusBounds.fBounds) {
1960 bounds = SkIRect::MakeWH(image->width(), image->height());
1961 latticePlusBounds.fBounds = &bounds;
1962 }
1963
1964 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1965 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001966 } else {
1967 this->drawImageRect(image, dst, paint);
1968 }
1969}
1970
reed41af9662015-01-05 07:49:08 -08001971void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001972 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001973 return;
1974 }
reed41af9662015-01-05 07:49:08 -08001975 this->onDrawBitmap(bitmap, dx, dy, paint);
1976}
1977
reede47829b2015-08-06 10:02:53 -07001978void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001979 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001980 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001981 return;
1982 }
reede47829b2015-08-06 10:02:53 -07001983 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001984}
1985
reed84984ef2015-07-17 07:09:43 -07001986void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1987 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001988 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001989}
1990
reede47829b2015-08-06 10:02:53 -07001991void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1992 SrcRectConstraint constraint) {
1993 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1994 constraint);
1995}
reede47829b2015-08-06 10:02:53 -07001996
reed41af9662015-01-05 07:49:08 -08001997void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1998 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001999 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002000 return;
2001 }
msarett552bca92016-08-03 06:53:26 -07002002 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2003 this->onDrawBitmapNine(bitmap, center, dst, paint);
2004 } else {
reeda5517e22015-07-14 10:54:12 -07002005 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002006 }
reed41af9662015-01-05 07:49:08 -08002007}
2008
msarettc573a402016-08-02 08:05:56 -07002009void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2010 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002011 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002012 return;
2013 }
msarett71df2d72016-09-30 12:41:42 -07002014
2015 SkIRect bounds;
2016 Lattice latticePlusBounds = lattice;
2017 if (!latticePlusBounds.fBounds) {
2018 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
2019 latticePlusBounds.fBounds = &bounds;
2020 }
2021
2022 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
2023 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002024 } else {
msarett16882062016-08-16 09:31:08 -07002025 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002026 }
msarettc573a402016-08-02 08:05:56 -07002027}
2028
reed71c3c762015-06-24 10:29:17 -07002029void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002030 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002031 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002032 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002033 if (count <= 0) {
2034 return;
2035 }
Joe Gregorioc4859072017-01-20 14:21:27 +00002036 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002037 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002038 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002039}
2040
reedf70b5312016-03-04 16:36:20 -08002041void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2042 if (key) {
2043 this->onDrawAnnotation(rect, key, value);
2044 }
2045}
2046
reede47829b2015-08-06 10:02:53 -07002047void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2048 const SkPaint* paint, SrcRectConstraint constraint) {
2049 if (src) {
2050 this->drawImageRect(image, *src, dst, paint, constraint);
2051 } else {
2052 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2053 dst, paint, constraint);
2054 }
2055}
2056void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2057 const SkPaint* paint, SrcRectConstraint constraint) {
2058 if (src) {
2059 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2060 } else {
2061 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2062 dst, paint, constraint);
2063 }
2064}
2065
tomhudsoncb3bd182016-05-18 07:24:16 -07002066void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2067 SkIRect layer_bounds = this->getTopLayerBounds();
2068 if (matrix) {
2069 *matrix = this->getTotalMatrix();
2070 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2071 }
2072 if (clip_bounds) {
2073 this->getClipDeviceBounds(clip_bounds);
2074 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2075 }
2076}
2077
reed@android.com8a1c16f2008-12-17 15:59:43 +00002078//////////////////////////////////////////////////////////////////////////////
2079// These are the virtual drawing methods
2080//////////////////////////////////////////////////////////////////////////////
2081
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002082void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002083 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002084 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2085 }
2086}
2087
reed41af9662015-01-05 07:49:08 -08002088void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002089 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002090 this->internalDrawPaint(paint);
2091}
2092
2093void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002094 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002095
2096 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002097 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002098 }
2099
reed@google.com4e2b3d32011-04-07 14:18:59 +00002100 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002101}
2102
reed41af9662015-01-05 07:49:08 -08002103void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2104 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002105 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002106 if ((long)count <= 0) {
2107 return;
2108 }
2109
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002110 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002111 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002112 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002113 // special-case 2 points (common for drawing a single line)
2114 if (2 == count) {
2115 r.set(pts[0], pts[1]);
2116 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002117 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002118 }
senorblanco87e066e2015-10-28 11:23:36 -07002119 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2120 return;
2121 }
2122 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002123 }
reed@google.coma584aed2012-05-16 14:06:02 +00002124
halcanary96fcdcc2015-08-27 07:41:13 -07002125 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002126
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002127 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002128
reed@android.com8a1c16f2008-12-17 15:59:43 +00002129 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002130 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002131 }
reed@google.com4b226022011-01-11 18:32:13 +00002132
reed@google.com4e2b3d32011-04-07 14:18:59 +00002133 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002134}
2135
reed4a167172016-08-18 17:15:25 -07002136static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2137 return ((intptr_t)paint.getImageFilter() |
2138#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2139 (intptr_t)canvas->getDrawFilter() |
2140#endif
2141 (intptr_t)paint.getLooper() ) != 0;
2142}
2143
reed41af9662015-01-05 07:49:08 -08002144void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002145 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002146 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002147 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002148 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002149 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2150 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2151 SkRect tmp(r);
2152 tmp.sort();
2153
senorblanco87e066e2015-10-28 11:23:36 -07002154 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2155 return;
2156 }
2157 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002158 }
reed@google.com4b226022011-01-11 18:32:13 +00002159
reed4a167172016-08-18 17:15:25 -07002160 if (needs_autodrawlooper(this, paint)) {
2161 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002162
reed4a167172016-08-18 17:15:25 -07002163 while (iter.next()) {
2164 iter.fDevice->drawRect(iter, r, looper.paint());
2165 }
2166
2167 LOOPER_END
2168 } else {
2169 this->predrawNotify(bounds, &paint, false);
2170 SkDrawIter iter(this);
2171 while (iter.next()) {
2172 iter.fDevice->drawRect(iter, r, paint);
2173 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002174 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002175}
2176
msarett44df6512016-08-25 13:54:30 -07002177void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2178 SkRect storage;
2179 SkRect regionRect = SkRect::Make(region.getBounds());
2180 const SkRect* bounds = nullptr;
2181 if (paint.canComputeFastBounds()) {
2182 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2183 return;
2184 }
2185 bounds = &regionRect;
2186 }
2187
2188 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2189
2190 while (iter.next()) {
2191 iter.fDevice->drawRegion(iter, region, looper.paint());
2192 }
2193
2194 LOOPER_END
2195}
2196
reed41af9662015-01-05 07:49:08 -08002197void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002198 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002199 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002200 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002201 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002202 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2203 return;
2204 }
2205 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002206 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002207
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002208 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002209
2210 while (iter.next()) {
2211 iter.fDevice->drawOval(iter, oval, looper.paint());
2212 }
2213
2214 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002215}
2216
bsalomonac3aa242016-08-19 11:25:19 -07002217void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2218 SkScalar sweepAngle, bool useCenter,
2219 const SkPaint& paint) {
2220 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2221 const SkRect* bounds = nullptr;
2222 if (paint.canComputeFastBounds()) {
2223 SkRect storage;
2224 // Note we're using the entire oval as the bounds.
2225 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2226 return;
2227 }
2228 bounds = &oval;
2229 }
2230
2231 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2232
2233 while (iter.next()) {
2234 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2235 }
2236
2237 LOOPER_END
2238}
2239
reed41af9662015-01-05 07:49:08 -08002240void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002241 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002242 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002243 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002244 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002245 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2246 return;
2247 }
2248 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002249 }
2250
2251 if (rrect.isRect()) {
2252 // call the non-virtual version
2253 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002254 return;
2255 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002256 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002257 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2258 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002259 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002260
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002261 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002262
2263 while (iter.next()) {
2264 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2265 }
2266
2267 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002268}
2269
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002270void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2271 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002272 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002273 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002274 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002275 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2276 return;
2277 }
2278 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002279 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002280
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002281 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002282
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002283 while (iter.next()) {
2284 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2285 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002286
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002287 LOOPER_END
2288}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002289
reed41af9662015-01-05 07:49:08 -08002290void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002291 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002292 if (!path.isFinite()) {
2293 return;
2294 }
2295
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002296 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002297 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002298 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002299 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002300 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2301 return;
2302 }
2303 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002304 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002305
2306 const SkRect& r = path.getBounds();
2307 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002308 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002309 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002310 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002311 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002312 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002313
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002314 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002315
2316 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002317 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318 }
2319
reed@google.com4e2b3d32011-04-07 14:18:59 +00002320 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002321}
2322
reed262a71b2015-12-05 13:07:27 -08002323bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002324 if (!paint.getImageFilter()) {
2325 return false;
2326 }
2327
2328 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002329 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002330 return false;
2331 }
2332
2333 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2334 // Once we can filter and the filter will return a result larger than itself, we should be
2335 // able to remove this constraint.
2336 // skbug.com/4526
2337 //
2338 SkPoint pt;
2339 ctm.mapXY(x, y, &pt);
2340 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2341 return ir.contains(fMCRec->fRasterClip.getBounds());
2342}
2343
reeda85d4d02015-05-06 12:56:48 -07002344void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002345 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002346 SkRect bounds = SkRect::MakeXYWH(x, y,
2347 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002348 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002349 SkRect tmp = bounds;
2350 if (paint) {
2351 paint->computeFastBounds(tmp, &tmp);
2352 }
2353 if (this->quickReject(tmp)) {
2354 return;
2355 }
reeda85d4d02015-05-06 12:56:48 -07002356 }
halcanary9d524f22016-03-29 09:03:52 -07002357
reeda85d4d02015-05-06 12:56:48 -07002358 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002359 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002360 paint = lazy.init();
2361 }
reed262a71b2015-12-05 13:07:27 -08002362
reeda2217ef2016-07-20 06:04:34 -07002363 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002364 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2365 *paint);
2366 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002367 special = this->getDevice()->makeSpecial(image);
2368 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002369 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002370 }
2371 }
2372
reed262a71b2015-12-05 13:07:27 -08002373 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2374
reeda85d4d02015-05-06 12:56:48 -07002375 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002376 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002377 if (special) {
2378 SkPoint pt;
2379 iter.fMatrix->mapXY(x, y, &pt);
2380 iter.fDevice->drawSpecial(iter, special.get(),
2381 SkScalarRoundToInt(pt.fX),
2382 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002383 } else {
2384 iter.fDevice->drawImage(iter, image, x, y, pnt);
2385 }
reeda85d4d02015-05-06 12:56:48 -07002386 }
halcanary9d524f22016-03-29 09:03:52 -07002387
reeda85d4d02015-05-06 12:56:48 -07002388 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002389}
2390
reed41af9662015-01-05 07:49:08 -08002391void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002392 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002393 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002394 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002395 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002396 if (paint) {
2397 paint->computeFastBounds(dst, &storage);
2398 }
2399 if (this->quickReject(storage)) {
2400 return;
2401 }
reeda85d4d02015-05-06 12:56:48 -07002402 }
2403 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002404 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002405 paint = lazy.init();
2406 }
halcanary9d524f22016-03-29 09:03:52 -07002407
senorblancoc41e7e12015-12-07 12:51:30 -08002408 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002409 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002410
reeda85d4d02015-05-06 12:56:48 -07002411 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002412 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002413 }
halcanary9d524f22016-03-29 09:03:52 -07002414
reeda85d4d02015-05-06 12:56:48 -07002415 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002416}
2417
reed41af9662015-01-05 07:49:08 -08002418void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002419 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002420 SkDEBUGCODE(bitmap.validate();)
2421
reed33366972015-10-08 09:22:02 -07002422 if (bitmap.drawsNothing()) {
2423 return;
2424 }
2425
2426 SkLazyPaint lazy;
2427 if (nullptr == paint) {
2428 paint = lazy.init();
2429 }
2430
2431 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2432
2433 SkRect storage;
2434 const SkRect* bounds = nullptr;
2435 if (paint->canComputeFastBounds()) {
2436 bitmap.getBounds(&storage);
2437 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002438 SkRect tmp = storage;
2439 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2440 return;
2441 }
2442 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002443 }
reed@google.com4b226022011-01-11 18:32:13 +00002444
reeda2217ef2016-07-20 06:04:34 -07002445 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002446 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2447 *paint);
2448 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002449 special = this->getDevice()->makeSpecial(bitmap);
2450 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002451 drawAsSprite = false;
2452 }
2453 }
2454
reed262a71b2015-12-05 13:07:27 -08002455 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002456
2457 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002458 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002459 if (special) {
reed262a71b2015-12-05 13:07:27 -08002460 SkPoint pt;
2461 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002462 iter.fDevice->drawSpecial(iter, special.get(),
2463 SkScalarRoundToInt(pt.fX),
2464 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002465 } else {
2466 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2467 }
reed33366972015-10-08 09:22:02 -07002468 }
msarettfbfa2582016-08-12 08:29:08 -07002469
reed33366972015-10-08 09:22:02 -07002470 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002471}
2472
reed@google.com9987ec32011-09-07 11:57:52 +00002473// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002474void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002475 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002476 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002477 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002478 return;
2479 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002480
halcanary96fcdcc2015-08-27 07:41:13 -07002481 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002482 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002483 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2484 return;
2485 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002486 }
reed@google.com3d608122011-11-21 15:16:16 +00002487
reed@google.com33535f32012-09-25 15:37:50 +00002488 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002489 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002490 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002491 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002492
senorblancoc41e7e12015-12-07 12:51:30 -08002493 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002494 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002495
reed@google.com33535f32012-09-25 15:37:50 +00002496 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002497 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002498 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002499
reed@google.com33535f32012-09-25 15:37:50 +00002500 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002501}
2502
reed41af9662015-01-05 07:49:08 -08002503void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002504 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002505 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002506 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002507 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002508}
2509
reed4c21dc52015-06-25 12:32:03 -07002510void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2511 const SkPaint* paint) {
2512 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002513
halcanary96fcdcc2015-08-27 07:41:13 -07002514 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002515 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002516 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2517 return;
2518 }
reed@google.com3d608122011-11-21 15:16:16 +00002519 }
halcanary9d524f22016-03-29 09:03:52 -07002520
reed4c21dc52015-06-25 12:32:03 -07002521 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002522 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002523 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002524 }
halcanary9d524f22016-03-29 09:03:52 -07002525
senorblancoc41e7e12015-12-07 12:51:30 -08002526 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002527
reed4c21dc52015-06-25 12:32:03 -07002528 while (iter.next()) {
2529 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002530 }
halcanary9d524f22016-03-29 09:03:52 -07002531
reed4c21dc52015-06-25 12:32:03 -07002532 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002533}
2534
reed41af9662015-01-05 07:49:08 -08002535void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2536 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002537 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002538 SkDEBUGCODE(bitmap.validate();)
2539
halcanary96fcdcc2015-08-27 07:41:13 -07002540 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002541 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002542 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2543 return;
2544 }
reed4c21dc52015-06-25 12:32:03 -07002545 }
halcanary9d524f22016-03-29 09:03:52 -07002546
reed4c21dc52015-06-25 12:32:03 -07002547 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002548 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002549 paint = lazy.init();
2550 }
halcanary9d524f22016-03-29 09:03:52 -07002551
senorblancoc41e7e12015-12-07 12:51:30 -08002552 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002553
reed4c21dc52015-06-25 12:32:03 -07002554 while (iter.next()) {
2555 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2556 }
halcanary9d524f22016-03-29 09:03:52 -07002557
reed4c21dc52015-06-25 12:32:03 -07002558 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002559}
2560
msarett16882062016-08-16 09:31:08 -07002561void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2562 const SkPaint* paint) {
2563 if (nullptr == paint || paint->canComputeFastBounds()) {
2564 SkRect storage;
2565 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2566 return;
2567 }
2568 }
2569
2570 SkLazyPaint lazy;
2571 if (nullptr == paint) {
2572 paint = lazy.init();
2573 }
2574
2575 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2576
2577 while (iter.next()) {
2578 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2579 }
2580
2581 LOOPER_END
2582}
2583
2584void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2585 const SkRect& dst, const SkPaint* paint) {
2586 if (nullptr == paint || paint->canComputeFastBounds()) {
2587 SkRect storage;
2588 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2589 return;
2590 }
2591 }
2592
2593 SkLazyPaint lazy;
2594 if (nullptr == paint) {
2595 paint = lazy.init();
2596 }
2597
2598 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2599
2600 while (iter.next()) {
2601 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2602 }
2603
2604 LOOPER_END
2605}
2606
reed@google.comf67e4cf2011-03-15 20:56:58 +00002607class SkDeviceFilteredPaint {
2608public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002609 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002610 uint32_t filteredFlags = device->filterTextFlags(paint);
2611 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002612 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002613 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002614 fPaint = newPaint;
2615 } else {
2616 fPaint = &paint;
2617 }
2618 }
2619
reed@google.comf67e4cf2011-03-15 20:56:58 +00002620 const SkPaint& paint() const { return *fPaint; }
2621
2622private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002623 const SkPaint* fPaint;
2624 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002625};
2626
bungeman@google.com52c748b2011-08-22 21:30:43 +00002627void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2628 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002629 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002630 draw.fDevice->drawRect(draw, r, paint);
2631 } else {
2632 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002633 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002634 draw.fDevice->drawRect(draw, r, p);
2635 }
2636}
2637
2638void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2639 const char text[], size_t byteLength,
2640 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002641 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002642
2643 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002644 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002645 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002646 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002647 return;
2648 }
2649
2650 SkScalar width = 0;
2651 SkPoint start;
2652
2653 start.set(0, 0); // to avoid warning
2654 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2655 SkPaint::kStrikeThruText_Flag)) {
2656 width = paint.measureText(text, byteLength);
2657
2658 SkScalar offsetX = 0;
2659 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2660 offsetX = SkScalarHalf(width);
2661 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2662 offsetX = width;
2663 }
2664 start.set(x - offsetX, y);
2665 }
2666
2667 if (0 == width) {
2668 return;
2669 }
2670
2671 uint32_t flags = paint.getFlags();
2672
2673 if (flags & (SkPaint::kUnderlineText_Flag |
2674 SkPaint::kStrikeThruText_Flag)) {
2675 SkScalar textSize = paint.getTextSize();
2676 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2677 SkRect r;
2678
2679 r.fLeft = start.fX;
2680 r.fRight = start.fX + width;
2681
2682 if (flags & SkPaint::kUnderlineText_Flag) {
2683 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2684 start.fY);
2685 r.fTop = offset;
2686 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002687 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002688 }
2689 if (flags & SkPaint::kStrikeThruText_Flag) {
2690 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2691 start.fY);
2692 r.fTop = offset;
2693 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002694 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002695 }
2696 }
2697}
2698
reed@google.come0d9ce82014-04-23 04:00:17 +00002699void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2700 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002701 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002702
2703 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002704 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002705 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002706 DrawTextDecorations(iter, dfp.paint(),
2707 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002708 }
2709
reed@google.com4e2b3d32011-04-07 14:18:59 +00002710 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002711}
2712
reed@google.come0d9ce82014-04-23 04:00:17 +00002713void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2714 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002715 SkPoint textOffset = SkPoint::Make(0, 0);
2716
halcanary96fcdcc2015-08-27 07:41:13 -07002717 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002718
reed@android.com8a1c16f2008-12-17 15:59:43 +00002719 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002720 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002721 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002722 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002723 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002724
reed@google.com4e2b3d32011-04-07 14:18:59 +00002725 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002726}
2727
reed@google.come0d9ce82014-04-23 04:00:17 +00002728void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2729 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002730
2731 SkPoint textOffset = SkPoint::Make(0, constY);
2732
halcanary96fcdcc2015-08-27 07:41:13 -07002733 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002734
reed@android.com8a1c16f2008-12-17 15:59:43 +00002735 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002736 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002737 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002738 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002739 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002740
reed@google.com4e2b3d32011-04-07 14:18:59 +00002741 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002742}
2743
reed@google.come0d9ce82014-04-23 04:00:17 +00002744void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2745 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002746 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002747
reed@android.com8a1c16f2008-12-17 15:59:43 +00002748 while (iter.next()) {
2749 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002750 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002751 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002752
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002753 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002754}
2755
reed45561a02016-07-07 12:47:17 -07002756void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2757 const SkRect* cullRect, const SkPaint& paint) {
2758 if (cullRect && this->quickReject(*cullRect)) {
2759 return;
2760 }
2761
2762 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2763
2764 while (iter.next()) {
2765 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2766 }
2767
2768 LOOPER_END
2769}
2770
fmalita00d5c2c2014-08-21 08:53:26 -07002771void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2772 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002773
fmalita85d5eb92015-03-04 11:20:12 -08002774 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002775 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002776 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002777 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002778 SkRect tmp;
2779 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2780 return;
2781 }
2782 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002783 }
2784
fmalita024f9962015-03-03 19:08:17 -08002785 // We cannot filter in the looper as we normally do, because the paint is
2786 // incomplete at this point (text-related attributes are embedded within blob run paints).
2787 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002788 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002789
fmalita85d5eb92015-03-04 11:20:12 -08002790 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002791
fmalitaaa1b9122014-08-28 14:32:24 -07002792 while (iter.next()) {
2793 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002794 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002795 }
2796
fmalitaaa1b9122014-08-28 14:32:24 -07002797 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002798
2799 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002800}
2801
reed@google.come0d9ce82014-04-23 04:00:17 +00002802// These will become non-virtual, so they always call the (virtual) onDraw... method
2803void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2804 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002805 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002806 if (byteLength) {
2807 this->onDrawText(text, byteLength, x, y, paint);
2808 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002809}
2810void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2811 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002812 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002813 if (byteLength) {
2814 this->onDrawPosText(text, byteLength, pos, paint);
2815 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002816}
2817void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2818 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002819 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002820 if (byteLength) {
2821 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2822 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002823}
2824void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2825 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002826 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002827 if (byteLength) {
2828 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2829 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002830}
reed45561a02016-07-07 12:47:17 -07002831void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2832 const SkRect* cullRect, const SkPaint& paint) {
2833 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2834 if (byteLength) {
2835 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2836 }
2837}
fmalita00d5c2c2014-08-21 08:53:26 -07002838void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2839 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002840 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002841 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002842 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002843}
reed@google.come0d9ce82014-04-23 04:00:17 +00002844
reed41af9662015-01-05 07:49:08 -08002845void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2846 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002847 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002848 const uint16_t indices[], int indexCount,
2849 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002850 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002851 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002852
reed@android.com8a1c16f2008-12-17 15:59:43 +00002853 while (iter.next()) {
2854 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002855 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002856 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002857 }
reed@google.com4b226022011-01-11 18:32:13 +00002858
reed@google.com4e2b3d32011-04-07 14:18:59 +00002859 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002860}
2861
dandovb3c9d1c2014-08-12 08:34:29 -07002862void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002863 const SkPoint texCoords[4], SkBlendMode bmode,
2864 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002865 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002866 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002867 return;
2868 }
mtklein6cfa73a2014-08-13 13:33:49 -07002869
Mike Reedfaba3712016-11-03 14:45:31 -04002870 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002871}
2872
2873void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002874 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002875 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002876 // Since a patch is always within the convex hull of the control points, we discard it when its
2877 // bounding rectangle is completely outside the current clip.
2878 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002879 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002880 if (this->quickReject(bounds)) {
2881 return;
2882 }
mtklein6cfa73a2014-08-13 13:33:49 -07002883
halcanary96fcdcc2015-08-27 07:41:13 -07002884 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002885
dandovecfff212014-08-04 10:02:00 -07002886 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002887 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002888 }
mtklein6cfa73a2014-08-13 13:33:49 -07002889
dandovecfff212014-08-04 10:02:00 -07002890 LOOPER_END
2891}
2892
reeda8db7282015-07-07 10:22:31 -07002893void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002894 RETURN_ON_NULL(dr);
2895 if (x || y) {
2896 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2897 this->onDrawDrawable(dr, &matrix);
2898 } else {
2899 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002900 }
2901}
2902
reeda8db7282015-07-07 10:22:31 -07002903void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002904 RETURN_ON_NULL(dr);
2905 if (matrix && matrix->isIdentity()) {
2906 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002907 }
reede3b38ce2016-01-08 09:18:44 -08002908 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002909}
2910
2911void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002912 // drawable bounds are no longer reliable (e.g. android displaylist)
2913 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002914 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002915}
2916
reed71c3c762015-06-24 10:29:17 -07002917void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002918 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002919 const SkRect* cull, const SkPaint* paint) {
2920 if (cull && this->quickReject(*cull)) {
2921 return;
2922 }
2923
2924 SkPaint pnt;
2925 if (paint) {
2926 pnt = *paint;
2927 }
halcanary9d524f22016-03-29 09:03:52 -07002928
halcanary96fcdcc2015-08-27 07:41:13 -07002929 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002930 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002931 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002932 }
2933 LOOPER_END
2934}
2935
reedf70b5312016-03-04 16:36:20 -08002936void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2937 SkASSERT(key);
2938
2939 SkPaint paint;
2940 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2941 while (iter.next()) {
2942 iter.fDevice->drawAnnotation(iter, rect, key, value);
2943 }
2944 LOOPER_END
2945}
2946
reed@android.com8a1c16f2008-12-17 15:59:43 +00002947//////////////////////////////////////////////////////////////////////////////
2948// These methods are NOT virtual, and therefore must call back into virtual
2949// methods, rather than actually drawing themselves.
2950//////////////////////////////////////////////////////////////////////////////
2951
reed374772b2016-10-05 17:33:02 -07002952void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002953 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002954 SkPaint paint;
2955
2956 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002957 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002958 this->drawPaint(paint);
2959}
2960
reed374772b2016-10-05 17:33:02 -07002961void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002962 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002963 SkPaint paint;
2964
2965 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002966 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002967 this->drawPaint(paint);
2968}
2969
2970void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002971 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002972 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002973
reed@android.com8a1c16f2008-12-17 15:59:43 +00002974 pt.set(x, y);
2975 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2976}
2977
2978void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002979 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002980 SkPoint pt;
2981 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002982
reed@android.com8a1c16f2008-12-17 15:59:43 +00002983 pt.set(x, y);
2984 paint.setColor(color);
2985 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2986}
2987
2988void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2989 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002990 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002991 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002992
reed@android.com8a1c16f2008-12-17 15:59:43 +00002993 pts[0].set(x0, y0);
2994 pts[1].set(x1, y1);
2995 this->drawPoints(kLines_PointMode, 2, pts, paint);
2996}
2997
2998void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2999 SkScalar right, SkScalar bottom,
3000 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003001 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003002 SkRect r;
3003
3004 r.set(left, top, right, bottom);
3005 this->drawRect(r, paint);
3006}
3007
3008void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3009 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003010 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003011 if (radius < 0) {
3012 radius = 0;
3013 }
3014
3015 SkRect r;
3016 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003017 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003018}
3019
3020void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3021 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003022 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003023 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003024 SkRRect rrect;
3025 rrect.setRectXY(r, rx, ry);
3026 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003027 } else {
3028 this->drawRect(r, paint);
3029 }
3030}
3031
reed@android.com8a1c16f2008-12-17 15:59:43 +00003032void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3033 SkScalar sweepAngle, bool useCenter,
3034 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003035 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003036 if (oval.isEmpty() || !sweepAngle) {
3037 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003038 }
bsalomon21af9ca2016-08-25 12:29:23 -07003039 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003040}
3041
3042void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3043 const SkPath& path, SkScalar hOffset,
3044 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003045 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003046 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003047
reed@android.com8a1c16f2008-12-17 15:59:43 +00003048 matrix.setTranslate(hOffset, vOffset);
3049 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3050}
3051
reed@android.comf76bacf2009-05-13 14:00:33 +00003052///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003053
3054/**
3055 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3056 * against the playback cost of recursing into the subpicture to get at its actual ops.
3057 *
3058 * For now we pick a conservatively small value, though measurement (and other heuristics like
3059 * the type of ops contained) may justify changing this value.
3060 */
3061#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003062
reedd5fa1a42014-08-09 11:08:05 -07003063void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003064 RETURN_ON_NULL(picture);
3065
reed1c2c4412015-04-30 13:09:24 -07003066 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003067 if (matrix && matrix->isIdentity()) {
3068 matrix = nullptr;
3069 }
3070 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3071 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3072 picture->playback(this);
3073 } else {
3074 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003075 }
3076}
robertphillips9b14f262014-06-04 05:40:44 -07003077
reedd5fa1a42014-08-09 11:08:05 -07003078void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3079 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003080 if (!paint || paint->canComputeFastBounds()) {
3081 SkRect bounds = picture->cullRect();
3082 if (paint) {
3083 paint->computeFastBounds(bounds, &bounds);
3084 }
3085 if (matrix) {
3086 matrix->mapRect(&bounds);
3087 }
3088 if (this->quickReject(bounds)) {
3089 return;
3090 }
3091 }
3092
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003093 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003094 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003095}
3096
vjiaoblack95302da2016-07-21 10:25:54 -07003097#ifdef SK_EXPERIMENTAL_SHADOWING
3098void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3099 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003100 const SkPaint* paint,
3101 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003102 RETURN_ON_NULL(picture);
3103
3104 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3105
vjiaoblacke6f5d562016-08-25 06:30:23 -07003106 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003107}
3108
3109void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3110 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003111 const SkPaint* paint,
3112 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003113 if (!paint || paint->canComputeFastBounds()) {
3114 SkRect bounds = picture->cullRect();
3115 if (paint) {
3116 paint->computeFastBounds(bounds, &bounds);
3117 }
3118 if (matrix) {
3119 matrix->mapRect(&bounds);
3120 }
3121 if (this->quickReject(bounds)) {
3122 return;
3123 }
3124 }
3125
3126 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3127
vjiaoblacke6f5d562016-08-25 06:30:23 -07003128 sk_sp<SkImage> povDepthMap;
3129 sk_sp<SkImage> diffuseMap;
3130
vjiaoblack904527d2016-08-09 09:32:09 -07003131 // povDepthMap
3132 {
3133 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003134 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3135 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003136 sk_sp<SkLights> povLight = builder.finish();
3137
3138 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3139 picture->cullRect().height(),
3140 kBGRA_8888_SkColorType,
3141 kOpaque_SkAlphaType);
3142
3143 // Create a new surface (that matches the backend of canvas)
3144 // to create the povDepthMap
3145 sk_sp<SkSurface> surf(this->makeSurface(info));
3146
3147 // Wrap another SPFCanvas around the surface
3148 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3149 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3150
3151 // set the depth map canvas to have the light as the user's POV
3152 depthMapCanvas->setLights(std::move(povLight));
3153
3154 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003155 povDepthMap = surf->makeImageSnapshot();
3156 }
3157
3158 // diffuseMap
3159 {
3160 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3161 picture->cullRect().height(),
3162 kBGRA_8888_SkColorType,
3163 kOpaque_SkAlphaType);
3164
3165 sk_sp<SkSurface> surf(this->makeSurface(info));
3166 surf->getCanvas()->drawPicture(picture);
3167
3168 diffuseMap = surf->makeImageSnapshot();
3169 }
vjiaoblack904527d2016-08-09 09:32:09 -07003170
3171 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3172 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003173 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3174 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003175
3176 // TODO: pass the depth to the shader in vertices, or uniforms
3177 // so we don't have to render depth and color separately
3178 for (int i = 0; i < fLights->numLights(); ++i) {
3179 // skip over ambient lights; they don't cast shadows
3180 // lights that have shadow maps do not need updating (because lights are immutable)
3181 sk_sp<SkImage> depthMap;
3182 SkISize shMapSize;
3183
3184 if (fLights->light(i).getShadowMap() != nullptr) {
3185 continue;
3186 }
3187
3188 if (fLights->light(i).isRadial()) {
3189 shMapSize.fHeight = 1;
3190 shMapSize.fWidth = (int) picture->cullRect().width();
3191
3192 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3193 kBGRA_8888_SkColorType,
3194 kOpaque_SkAlphaType);
3195
3196 // Create new surface (that matches the backend of canvas)
3197 // for each shadow map
3198 sk_sp<SkSurface> surf(this->makeSurface(info));
3199
3200 // Wrap another SPFCanvas around the surface
3201 SkCanvas* depthMapCanvas = surf->getCanvas();
3202
3203 SkLights::Builder builder;
3204 builder.add(fLights->light(i));
3205 sk_sp<SkLights> curLight = builder.finish();
3206
3207 sk_sp<SkShader> shadowMapShader;
3208 shadowMapShader = SkRadialShadowMapShader::Make(
3209 povDepthShader, curLight,
3210 (int) picture->cullRect().width(),
3211 (int) picture->cullRect().height());
3212
3213 SkPaint shadowMapPaint;
3214 shadowMapPaint.setShader(std::move(shadowMapShader));
3215
3216 depthMapCanvas->setLights(curLight);
3217
3218 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3219 diffuseMap->height()),
3220 shadowMapPaint);
3221
3222 depthMap = surf->makeImageSnapshot();
3223
3224 } else {
3225 // TODO: compute the correct size of the depth map from the light properties
3226 // TODO: maybe add a kDepth_8_SkColorType
3227 // TODO: find actual max depth of picture
3228 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3229 fLights->light(i), 255,
3230 (int) picture->cullRect().width(),
3231 (int) picture->cullRect().height());
3232
3233 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3234 kBGRA_8888_SkColorType,
3235 kOpaque_SkAlphaType);
3236
3237 // Create a new surface (that matches the backend of canvas)
3238 // for each shadow map
3239 sk_sp<SkSurface> surf(this->makeSurface(info));
3240
3241 // Wrap another SPFCanvas around the surface
3242 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3243 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3244 depthMapCanvas->setShadowParams(params);
3245
3246 // set the depth map canvas to have the light we're drawing.
3247 SkLights::Builder builder;
3248 builder.add(fLights->light(i));
3249 sk_sp<SkLights> curLight = builder.finish();
3250 depthMapCanvas->setLights(std::move(curLight));
3251
3252 depthMapCanvas->drawPicture(picture);
3253 depthMap = surf->makeImageSnapshot();
3254 }
3255
3256 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3257 fLights->light(i).setShadowMap(std::move(depthMap));
3258 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3259 // we blur the variance map
3260 SkPaint blurPaint;
3261 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3262 params.fShadowRadius, nullptr));
3263
3264 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3265 kBGRA_8888_SkColorType,
3266 kOpaque_SkAlphaType);
3267
3268 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3269
3270 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3271
3272 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3273 }
3274 }
3275
3276 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003277 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3278 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003279 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003280 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003281 diffuseMap->height(),
3282 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003283
3284 shadowPaint.setShader(shadowShader);
3285
3286 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003287}
3288#endif
3289
reed@android.com8a1c16f2008-12-17 15:59:43 +00003290///////////////////////////////////////////////////////////////////////////////
3291///////////////////////////////////////////////////////////////////////////////
3292
reed3aafe112016-08-18 12:45:34 -07003293SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003294 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003295
3296 SkASSERT(canvas);
3297
reed3aafe112016-08-18 12:45:34 -07003298 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003299 fDone = !fImpl->next();
3300}
3301
3302SkCanvas::LayerIter::~LayerIter() {
3303 fImpl->~SkDrawIter();
3304}
3305
3306void SkCanvas::LayerIter::next() {
3307 fDone = !fImpl->next();
3308}
3309
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003310SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003311 return fImpl->getDevice();
3312}
3313
3314const SkMatrix& SkCanvas::LayerIter::matrix() const {
3315 return fImpl->getMatrix();
3316}
3317
3318const SkPaint& SkCanvas::LayerIter::paint() const {
3319 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003320 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003321 paint = &fDefaultPaint;
3322 }
3323 return *paint;
3324}
3325
reed1e7f5e72016-04-27 07:49:17 -07003326const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003327int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3328int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003329
3330///////////////////////////////////////////////////////////////////////////////
3331
fmalitac3b589a2014-06-05 12:40:07 -07003332SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003333
3334///////////////////////////////////////////////////////////////////////////////
3335
3336static bool supported_for_raster_canvas(const SkImageInfo& info) {
3337 switch (info.alphaType()) {
3338 case kPremul_SkAlphaType:
3339 case kOpaque_SkAlphaType:
3340 break;
3341 default:
3342 return false;
3343 }
3344
3345 switch (info.colorType()) {
3346 case kAlpha_8_SkColorType:
3347 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003348 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003349 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003350 break;
3351 default:
3352 return false;
3353 }
3354
3355 return true;
3356}
3357
Mike Reed5df49342016-11-12 08:06:55 -06003358std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3359 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003360 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003361 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003362 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003363
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003364 SkBitmap bitmap;
3365 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003366 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003367 }
Mike Reed5df49342016-11-12 08:06:55 -06003368 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003369}
reedd5fa1a42014-08-09 11:08:05 -07003370
3371///////////////////////////////////////////////////////////////////////////////
3372
3373SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003374 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003375 : fCanvas(canvas)
3376 , fSaveCount(canvas->getSaveCount())
3377{
bsalomon49f085d2014-09-05 13:34:00 -07003378 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003379 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003380 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003381 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003382 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003383 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003384 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003385 canvas->save();
3386 }
mtklein6cfa73a2014-08-13 13:33:49 -07003387
bsalomon49f085d2014-09-05 13:34:00 -07003388 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003389 canvas->concat(*matrix);
3390 }
3391}
3392
3393SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3394 fCanvas->restoreToCount(fSaveCount);
3395}
reede8f30622016-03-23 18:59:25 -07003396
Florin Malitaee424ac2016-12-01 12:47:59 -05003397///////////////////////////////////////////////////////////////////////////////
3398
3399SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3400 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3401
Florin Malita439ace92016-12-02 12:05:41 -05003402SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3403 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3404
Florin Malitaee424ac2016-12-01 12:47:59 -05003405SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3406 (void)this->INHERITED::getSaveLayerStrategy(rec);
3407 return kNoLayer_SaveLayerStrategy;
3408}
3409
3410///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003411
reed73603f32016-09-20 08:42:38 -07003412static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3413static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3414static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3415static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3416static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3417static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");
Mike Reed356f7c22017-01-10 11:58:39 -05003418
3419///////////////////////////////////////////////////////////////////////////////////////////////////
3420
3421SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
3422 if (fAllocator && fMCRec->fTopLayer->fDevice) {
3423 const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
3424 SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
3425 SkIPoint origin = dev->getOrigin();
3426 SkMatrix ctm = this->getTotalMatrix();
3427 ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
3428
3429 SkIRect clip = fMCRec->fRasterClip.getBounds();
3430 clip.offset(-origin.x(), -origin.y());
Mike Reed108f55e2017-01-12 11:28:01 -05003431 if (!clip.intersect(0, 0, dev->width(), dev->height())) {
Mike Reed356f7c22017-01-10 11:58:39 -05003432 clip.setEmpty();
3433 }
3434
3435 fAllocator->updateHandle(handle, ctm, clip);
3436 return handle;
3437 }
3438 return nullptr;
3439}
3440
3441static bool install(SkBitmap* bm, const SkImageInfo& info,
3442 const SkRasterHandleAllocator::Rec& rec) {
3443 return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
3444 rec.fReleaseProc, rec.fReleaseCtx);
3445}
3446
3447SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
3448 SkBitmap* bm) {
3449 SkRasterHandleAllocator::Rec rec;
3450 if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
3451 return nullptr;
3452 }
3453 return rec.fHandle;
3454}
3455
3456std::unique_ptr<SkCanvas>
3457SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
3458 const SkImageInfo& info, const Rec* rec) {
3459 if (!alloc || !supported_for_raster_canvas(info)) {
3460 return nullptr;
3461 }
3462
3463 SkBitmap bm;
3464 Handle hndl;
3465
3466 if (rec) {
3467 hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
3468 } else {
3469 hndl = alloc->allocBitmap(info, &bm);
3470 }
3471 return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
3472}