blob: 31af0a10f3eac0dfc7242fc5e0873c9d95d8ddb2 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
bungemand3ebb482015-08-05 13:57:49 -07008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080017#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
msarettfbfa2582016-08-12 08:29:08 -070025#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070026#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070027#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000028#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070029#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000030#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080031#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000032#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070033#include "SkShadowPaintFilterCanvas.h"
34#include "SkShadowShader.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000035#include "SkSmallAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080036#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000037#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070038#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000039#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000040#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080041#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070042#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000044#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080045#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000046#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070047#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070048
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000049#endif
50
reede3b38ce2016-01-08 09:18:44 -080051#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
52
reedc83a2972015-07-16 07:40:45 -070053/*
54 * Return true if the drawing this rect would hit every pixels in the canvas.
55 *
56 * Returns false if
57 * - rect does not contain the canvas' bounds
58 * - paint is not fill
59 * - paint would blur or otherwise change the coverage of the rect
60 */
61bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
62 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070063 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
64 (int)kNone_ShaderOverrideOpacity,
65 "need_matching_enums0");
66 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
67 (int)kOpaque_ShaderOverrideOpacity,
68 "need_matching_enums1");
69 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
70 (int)kNotOpaque_ShaderOverrideOpacity,
71 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070072
73 const SkISize size = this->getBaseLayerSize();
74 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
75 if (!this->getClipStack()->quickContains(bounds)) {
76 return false;
77 }
78
79 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070080 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070081 return false; // conservative
82 }
halcanaryc5769b22016-08-10 07:13:21 -070083
84 SkRect devRect;
85 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
86 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070087 return false;
88 }
89 }
90
91 if (paint) {
92 SkPaint::Style paintStyle = paint->getStyle();
93 if (!(paintStyle == SkPaint::kFill_Style ||
94 paintStyle == SkPaint::kStrokeAndFill_Style)) {
95 return false;
96 }
97 if (paint->getMaskFilter() || paint->getLooper()
98 || paint->getPathEffect() || paint->getImageFilter()) {
99 return false; // conservative
100 }
101 }
102 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
103}
104
105///////////////////////////////////////////////////////////////////////////////////////////////////
106
reedd990e2f2014-12-22 11:58:30 -0800107static bool gIgnoreSaveLayerBounds;
108void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
109 gIgnoreSaveLayerBounds = ignore;
110}
111bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
112 return gIgnoreSaveLayerBounds;
113}
114
reed0acf1b42014-12-22 16:12:38 -0800115static bool gTreatSpriteAsBitmap;
116void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
117 gTreatSpriteAsBitmap = spriteAsBitmap;
118}
119bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
120 return gTreatSpriteAsBitmap;
121}
122
reed@google.comda17f752012-08-16 18:27:05 +0000123// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124//#define SK_TRACE_SAVERESTORE
125
126#ifdef SK_TRACE_SAVERESTORE
127 static int gLayerCounter;
128 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
129 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
130
131 static int gRecCounter;
132 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
133 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
134
135 static int gCanvasCounter;
136 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
137 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
138#else
139 #define inc_layer()
140 #define dec_layer()
141 #define inc_rec()
142 #define dec_rec()
143 #define inc_canvas()
144 #define dec_canvas()
145#endif
146
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000147typedef SkTLazy<SkPaint> SkLazyPaint;
148
reedc83a2972015-07-16 07:40:45 -0700149void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000150 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700151 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
152 ? SkSurface::kDiscard_ContentChangeMode
153 : SkSurface::kRetain_ContentChangeMode);
154 }
155}
156
157void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
158 ShaderOverrideOpacity overrideOpacity) {
159 if (fSurfaceBase) {
160 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
161 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
162 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
163 // and therefore we don't care which mode we're in.
164 //
165 if (fSurfaceBase->outstandingImageSnapshot()) {
166 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
167 mode = SkSurface::kDiscard_ContentChangeMode;
168 }
169 }
170 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000171 }
172}
173
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000176/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 The clip/matrix/proc are fields that reflect the top of the save/restore
178 stack. Whenever the canvas changes, it marks a dirty flag, and then before
179 these are used (assuming we're not on a layer) we rebuild these cache
180 values: they reflect the top of the save stack, but translated and clipped
181 by the device's XY offset and bitmap-bounds.
182*/
183struct DeviceCM {
184 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000185 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000186 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000187 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700188 const SkMatrix* fMatrix;
189 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700190 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191
reed96e657d2015-03-10 17:30:07 -0700192 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700193 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700194 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700195 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700196 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700197 {
reed2c9e2002016-07-25 08:05:22 -0700198 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000199 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700200 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000201 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000203 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700204 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700205 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000206 }
reed@google.com4b226022011-01-11 18:32:13 +0000207
mtkleinfeaadee2015-04-08 11:25:48 -0700208 void reset(const SkIRect& bounds) {
209 SkASSERT(!fPaint);
210 SkASSERT(!fNext);
211 SkASSERT(fDevice);
212 fClip.setRect(bounds);
213 }
214
reed@google.com045e62d2011-10-24 12:19:46 +0000215 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700216 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000217 int x = fDevice->getOrigin().x();
218 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 int width = fDevice->width();
220 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000221
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 if ((x | y) == 0) {
223 fMatrix = &totalMatrix;
224 fClip = totalClip;
225 } else {
226 fMatrixStorage = totalMatrix;
227 fMatrixStorage.postTranslate(SkIntToScalar(-x),
228 SkIntToScalar(-y));
229 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000230
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 totalClip.translate(-x, -y, &fClip);
232 }
233
reed@google.com045e62d2011-10-24 12:19:46 +0000234 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235
236 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000237
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000239 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 SkRegion::kDifference_Op);
241 }
reed@google.com4b226022011-01-11 18:32:13 +0000242
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243#ifdef SK_DEBUG
244 if (!fClip.isEmpty()) {
245 SkIRect deviceR;
246 deviceR.set(0, 0, width, height);
247 SkASSERT(deviceR.contains(fClip.getBounds()));
248 }
249#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000250 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251};
252
253/* This is the record we keep for each save/restore level in the stack.
254 Since a level optionally copies the matrix and/or stack, we have pointers
255 for these fields. If the value is copied for this level, the copy is
256 stored in the ...Storage field, and the pointer points to that. If the
257 value is not copied for this level, we ignore ...Storage, and just point
258 at the corresponding value in the previous level in the stack.
259*/
260class SkCanvas::MCRec {
261public:
reed1f836ee2014-07-07 07:49:34 -0700262 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700263 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264 /* If there are any layers in the stack, this points to the top-most
265 one that is at or below this level in the stack (so we know what
266 bitmap/device to draw into from this level. This value is NOT
267 reference counted, since the real owner is either our fLayer field,
268 or a previous one in a lower level.)
269 */
reed2ff1fce2014-12-11 07:07:37 -0800270 DeviceCM* fTopLayer;
271 SkRasterClip fRasterClip;
272 SkMatrix fMatrix;
273 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274
vjiaoblacke5de1302016-07-13 14:05:28 -0700275 // This is the current cumulative depth (aggregate of all done translateZ calls)
276 SkScalar fCurDrawDepth;
277
reedd9544982014-09-09 18:46:22 -0700278 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700279 fFilter = nullptr;
280 fLayer = nullptr;
281 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800282 fMatrix.reset();
283 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700284 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700285
reedd9544982014-09-09 18:46:22 -0700286 // don't bother initializing fNext
287 inc_rec();
288 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700289 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
290 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700291 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700292 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700293 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800294 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700295
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 // don't bother initializing fNext
297 inc_rec();
298 }
299 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000300 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700301 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302 dec_rec();
303 }
mtkleinfeaadee2015-04-08 11:25:48 -0700304
305 void reset(const SkIRect& bounds) {
306 SkASSERT(fLayer);
307 SkASSERT(fDeferredSaveCount == 0);
308
309 fMatrix.reset();
310 fRasterClip.setRect(bounds);
311 fLayer->reset(bounds);
312 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313};
314
reed02f9ed72016-09-06 09:06:18 -0700315static SkIRect compute_device_bounds(SkBaseDevice* device) {
316 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
317 device->width(), device->height());
318}
319
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320class SkDrawIter : public SkDraw {
321public:
reed3aafe112016-08-18 12:45:34 -0700322 SkDrawIter(SkCanvas* canvas) {
junov@google.com4370aed2012-01-18 16:21:08 +0000323 canvas = canvas->canvasForDrawIter();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324 canvas->updateDeviceCMCache();
325
reed687fa1c2015-04-07 08:00:56 -0700326 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700328
329 fMultiDeviceCS = nullptr;
330 if (fCurrLayer->fNext) {
331 fMultiDeviceCS = canvas->fClipStack;
332 fMultiDeviceCS->save();
333 }
334 }
335
336 ~SkDrawIter() {
337 if (fMultiDeviceCS) {
338 fMultiDeviceCS->restore();
339 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 }
reed@google.com4b226022011-01-11 18:32:13 +0000341
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700343 if (fMultiDeviceCS && fDevice) {
344 // remove the previous device's bounds
345 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice),
346 SkRegion::kDifference_Op);
347 }
348
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700350 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
351 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352 }
353
reed@google.comf68c5e22012-02-24 16:38:58 +0000354 const DeviceCM* rec = fCurrLayer;
355 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356
357 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000358 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700360 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700361 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700362 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000364 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365
366 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700367 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000368
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 return true;
370 }
371 return false;
372 }
reed@google.com4b226022011-01-11 18:32:13 +0000373
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000374 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700375 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000376 int getX() const { return fDevice->getOrigin().x(); }
377 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000380
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382 const DeviceCM* fCurrLayer;
383 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700384 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000385
386 typedef SkDraw INHERITED;
387};
388
389/////////////////////////////////////////////////////////////////////////////
390
reeddbc3cef2015-04-29 12:18:57 -0700391static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
392 return lazy->isValid() ? lazy->get() : lazy->set(orig);
393}
394
395/**
396 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700397 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700398 */
reedd053ce92016-03-22 10:17:23 -0700399static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700400 SkImageFilter* imgf = paint.getImageFilter();
401 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700402 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700403 }
404
reedd053ce92016-03-22 10:17:23 -0700405 SkColorFilter* imgCFPtr;
406 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700407 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700408 }
reedd053ce92016-03-22 10:17:23 -0700409 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700410
411 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700412 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700413 // there is no existing paint colorfilter, so we can just return the imagefilter's
414 return imgCF;
415 }
416
417 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
418 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700419 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700420}
421
senorblanco87e066e2015-10-28 11:23:36 -0700422/**
423 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
424 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
425 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
426 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
427 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
428 * conservative "effective" bounds based on the settings in the paint... with one exception. This
429 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
430 * deliberately ignored.
431 */
432static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
433 const SkRect& rawBounds,
434 SkRect* storage) {
435 SkPaint tmpUnfiltered(paint);
436 tmpUnfiltered.setImageFilter(nullptr);
437 if (tmpUnfiltered.canComputeFastBounds()) {
438 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
439 } else {
440 return rawBounds;
441 }
442}
443
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444class AutoDrawLooper {
445public:
senorblanco87e066e2015-10-28 11:23:36 -0700446 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
447 // paint. It's used to determine the size of the offscreen layer for filters.
448 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700449 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700450 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000451 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800452#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000453 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800454#else
455 fFilter = nullptr;
456#endif
reed4a8126e2014-09-22 07:29:03 -0700457 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000458 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700459 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000460 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000461
reedd053ce92016-03-22 10:17:23 -0700462 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700463 if (simplifiedCF) {
464 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700465 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700466 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700467 fPaint = paint;
468 }
469
470 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700471 /**
472 * We implement ImageFilters for a given draw by creating a layer, then applying the
473 * imagefilter to the pixels of that layer (its backing surface/image), and then
474 * we call restore() to xfer that layer to the main canvas.
475 *
476 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
477 * 2. Generate the src pixels:
478 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
479 * return (fPaint). We then draw the primitive (using srcover) into a cleared
480 * buffer/surface.
481 * 3. Restore the layer created in #1
482 * The imagefilter is passed the buffer/surface from the layer (now filled with the
483 * src pixels of the primitive). It returns a new "filtered" buffer, which we
484 * draw onto the previous layer using the xfermode from the original paint.
485 */
reed@google.com8926b162012-03-23 15:36:36 +0000486 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700487 tmp.setImageFilter(fPaint->getImageFilter());
reedcfb6bdf2016-03-29 11:32:50 -0700488 tmp.setXfermode(sk_ref_sp(fPaint->getXfermode()));
senorblanco87e066e2015-10-28 11:23:36 -0700489 SkRect storage;
490 if (rawBounds) {
491 // Make rawBounds include all paint outsets except for those due to image filters.
492 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
493 }
reedbfd5f172016-01-07 11:28:08 -0800494 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700495 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700496 fTempLayerForImageFilter = true;
497 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000498 }
499
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000500 if (SkDrawLooper* looper = paint.getLooper()) {
501 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
502 looper->contextSize());
503 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000504 fIsSimple = false;
505 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700506 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000507 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700508 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000509 }
510 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000511
reed@android.com8a1c16f2008-12-17 15:59:43 +0000512 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700513 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000514 fCanvas->internalRestore();
515 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000516 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000518
reed@google.com4e2b3d32011-04-07 14:18:59 +0000519 const SkPaint& paint() const {
520 SkASSERT(fPaint);
521 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000522 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000523
reed@google.com129ec222012-05-15 13:24:09 +0000524 bool next(SkDrawFilter::Type drawType) {
525 if (fDone) {
526 return false;
527 } else if (fIsSimple) {
528 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000529 return !fPaint->nothingToDraw();
530 } else {
531 return this->doNext(drawType);
532 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000533 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000534
reed@android.com8a1c16f2008-12-17 15:59:43 +0000535private:
reeddbc3cef2015-04-29 12:18:57 -0700536 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
537 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000538 SkCanvas* fCanvas;
539 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000540 SkDrawFilter* fFilter;
541 const SkPaint* fPaint;
542 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700543 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000544 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000545 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000546 SkDrawLooper::Context* fLooperContext;
547 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000548
549 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000550};
551
reed@google.com129ec222012-05-15 13:24:09 +0000552bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700553 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000554 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700555 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000556
reeddbc3cef2015-04-29 12:18:57 -0700557 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
558 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000559
reed5c476fb2015-04-20 08:04:21 -0700560 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700561 paint->setImageFilter(nullptr);
562 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000563 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000564
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000565 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000566 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000567 return false;
568 }
569 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000570 if (!fFilter->filter(paint, drawType)) {
571 fDone = true;
572 return false;
573 }
halcanary96fcdcc2015-08-27 07:41:13 -0700574 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000575 // no looper means we only draw once
576 fDone = true;
577 }
578 }
579 fPaint = paint;
580
581 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000582 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000583 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000584 }
585
586 // call this after any possible paint modifiers
587 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700588 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000589 return false;
590 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000591 return true;
592}
593
reed@android.com8a1c16f2008-12-17 15:59:43 +0000594////////// macros to place around the internal draw calls //////////////////
595
reed3aafe112016-08-18 12:45:34 -0700596#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
597 this->predrawNotify(); \
598 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
599 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800600 SkDrawIter iter(this);
601
602
reed@google.com8926b162012-03-23 15:36:36 +0000603#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000604 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700605 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000606 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000607 SkDrawIter iter(this);
608
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000609#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000610 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700611 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000612 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000613 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000614
reedc83a2972015-07-16 07:40:45 -0700615#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
616 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700617 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700618 while (looper.next(type)) { \
619 SkDrawIter iter(this);
620
reed@google.com4e2b3d32011-04-07 14:18:59 +0000621#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000622
623////////////////////////////////////////////////////////////////////////////
624
msarettfbfa2582016-08-12 08:29:08 -0700625static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
626 if (bounds.isEmpty()) {
627 return SkRect::MakeEmpty();
628 }
629
630 // Expand bounds out by 1 in case we are anti-aliasing. We store the
631 // bounds as floats to enable a faster quick reject implementation.
632 SkRect dst;
633 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
634 return dst;
635}
636
mtkleinfeaadee2015-04-08 11:25:48 -0700637void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
638 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700639 fClipStack->reset();
640 fMCRec->reset(bounds);
641
642 // We're peering through a lot of structs here. Only at this scope do we
643 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
644 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700645 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700646 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700647}
648
reedd9544982014-09-09 18:46:22 -0700649SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800650 if (device && device->forceConservativeRasterClip()) {
651 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
652 }
653 // Since init() is only called once by our constructors, it is safe to perform this
654 // const-cast.
655 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
656
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000657 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000658 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700659 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800660 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700661 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700662#ifdef SK_EXPERIMENTAL_SHADOWING
663 fLights = nullptr;
664#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665
halcanary385fe4d2015-08-26 13:07:48 -0700666 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700667
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700669 new (fMCRec) MCRec(fConservativeRasterClip);
msarett9637ea92016-08-18 14:03:30 -0700670 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000671
reeda499f902015-05-01 09:34:31 -0700672 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
673 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700674 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700675 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700676
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000678
halcanary96fcdcc2015-08-27 07:41:13 -0700679 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000680
reedf92c8662014-08-18 08:02:43 -0700681 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700682 // The root device and the canvas should always have the same pixel geometry
683 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700684 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800685 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700686 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700687 }
msarettfbfa2582016-08-12 08:29:08 -0700688
reedf92c8662014-08-18 08:02:43 -0700689 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000690}
691
reed@google.comcde92112011-07-06 20:00:52 +0000692SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000693 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700694 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800695 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000696{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000697 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000698
halcanary96fcdcc2015-08-27 07:41:13 -0700699 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000700}
701
reedd9544982014-09-09 18:46:22 -0700702static SkBitmap make_nopixels(int width, int height) {
703 SkBitmap bitmap;
704 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
705 return bitmap;
706}
707
708class SkNoPixelsBitmapDevice : public SkBitmapDevice {
709public:
robertphillipsfcf78292015-06-19 11:49:52 -0700710 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
711 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800712 {
713 this->setOrigin(bounds.x(), bounds.y());
714 }
reedd9544982014-09-09 18:46:22 -0700715
716private:
piotaixrb5fae932014-09-24 13:03:30 -0700717
reedd9544982014-09-09 18:46:22 -0700718 typedef SkBitmapDevice INHERITED;
719};
720
reed96a857e2015-01-25 10:33:58 -0800721SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000722 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800723 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800724 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000725{
726 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700727
halcanary385fe4d2015-08-26 13:07:48 -0700728 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
729 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700730}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000731
reed78e27682014-11-19 08:04:34 -0800732SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700733 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700734 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800735 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700736{
737 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700738
halcanary385fe4d2015-08-26 13:07:48 -0700739 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700740}
741
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000742SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000743 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700744 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800745 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000746{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000747 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700748
reedd9544982014-09-09 18:46:22 -0700749 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750}
751
robertphillipsfcf78292015-06-19 11:49:52 -0700752SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
753 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700754 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800755 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700756{
757 inc_canvas();
758
759 this->init(device, flags);
760}
761
reed4a8126e2014-09-22 07:29:03 -0700762SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700763 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700764 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800765 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700766{
767 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700768
halcanary385fe4d2015-08-26 13:07:48 -0700769 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700770 this->init(device, kDefault_InitFlags);
771}
reed29c857d2014-09-21 10:25:07 -0700772
reed4a8126e2014-09-22 07:29:03 -0700773SkCanvas::SkCanvas(const SkBitmap& bitmap)
774 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
775 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800776 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700777{
778 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700779
halcanary385fe4d2015-08-26 13:07:48 -0700780 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700781 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782}
783
784SkCanvas::~SkCanvas() {
785 // free up the contents of our deque
786 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000787
reed@android.com8a1c16f2008-12-17 15:59:43 +0000788 this->internalRestore(); // restore the last, since we're going away
789
halcanary385fe4d2015-08-26 13:07:48 -0700790 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000791
reed@android.com8a1c16f2008-12-17 15:59:43 +0000792 dec_canvas();
793}
794
fmalita53d9f1c2016-01-25 06:23:54 -0800795#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000796SkDrawFilter* SkCanvas::getDrawFilter() const {
797 return fMCRec->fFilter;
798}
799
800SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700801 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000802 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
803 return filter;
804}
fmalita77650002016-01-21 18:47:11 -0800805#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000807SkMetaData& SkCanvas::getMetaData() {
808 // metadata users are rare, so we lazily allocate it. If that changes we
809 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700810 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000811 fMetaData = new SkMetaData;
812 }
813 return *fMetaData;
814}
815
reed@android.com8a1c16f2008-12-17 15:59:43 +0000816///////////////////////////////////////////////////////////////////////////////
817
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000818void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700819 this->onFlush();
820}
821
822void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000823 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000824 if (device) {
825 device->flush();
826 }
827}
828
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000829SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000830 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000831 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
832}
833
senorblancoafc7cce2016-02-02 18:44:15 -0800834SkIRect SkCanvas::getTopLayerBounds() const {
835 SkBaseDevice* d = this->getTopDevice();
836 if (!d) {
837 return SkIRect::MakeEmpty();
838 }
839 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
840}
841
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000842SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000843 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000844 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845 SkASSERT(rec && rec->fLayer);
846 return rec->fLayer->fDevice;
847}
848
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000849SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000850 if (updateMatrixClip) {
851 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
852 }
reed@google.com9266fed2011-03-30 00:18:03 +0000853 return fMCRec->fTopLayer->fDevice;
854}
855
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000856bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700857 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000858 return false;
859 }
860
861 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700862 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700863 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000864 return false;
865 }
866 weAllocated = true;
867 }
868
reedcf01e312015-05-23 19:14:51 -0700869 SkAutoPixmapUnlock unlocker;
870 if (bitmap->requestLock(&unlocker)) {
871 const SkPixmap& pm = unlocker.pixmap();
872 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
873 return true;
874 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000875 }
876
877 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700878 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000879 }
880 return false;
881}
reed@google.com51df9e32010-12-23 19:29:18 +0000882
bsalomon@google.comc6980972011-11-02 19:57:21 +0000883bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000884 SkIRect r = srcRect;
885 const SkISize size = this->getBaseLayerSize();
886 if (!r.intersect(0, 0, size.width(), size.height())) {
887 bitmap->reset();
888 return false;
889 }
890
reed84825042014-09-02 12:50:45 -0700891 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000892 // bitmap will already be reset.
893 return false;
894 }
895 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
896 bitmap->reset();
897 return false;
898 }
899 return true;
900}
901
reed96472de2014-12-10 09:53:42 -0800902bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000903 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000904 if (!device) {
905 return false;
906 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000907 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800908
reed96472de2014-12-10 09:53:42 -0800909 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
910 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000911 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000912 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000913
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000914 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800915 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000916}
917
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000918bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700919 SkAutoPixmapUnlock unlocker;
920 if (bitmap.requestLock(&unlocker)) {
921 const SkPixmap& pm = unlocker.pixmap();
922 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000923 }
924 return false;
925}
926
927bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
928 int x, int y) {
929 switch (origInfo.colorType()) {
930 case kUnknown_SkColorType:
931 case kIndex_8_SkColorType:
932 return false;
933 default:
934 break;
935 }
halcanary96fcdcc2015-08-27 07:41:13 -0700936 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000937 return false;
938 }
939
940 const SkISize size = this->getBaseLayerSize();
941 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
942 if (!target.intersect(0, 0, size.width(), size.height())) {
943 return false;
944 }
945
946 SkBaseDevice* device = this->getDevice();
947 if (!device) {
948 return false;
949 }
950
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000951 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700952 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000953
954 // if x or y are negative, then we have to adjust pixels
955 if (x > 0) {
956 x = 0;
957 }
958 if (y > 0) {
959 y = 0;
960 }
961 // here x,y are either 0 or negative
962 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
963
reed4af35f32014-06-27 17:47:49 -0700964 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700965 const bool completeOverwrite = info.dimensions() == size;
966 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700967
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000968 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000969 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000970}
reed@google.com51df9e32010-12-23 19:29:18 +0000971
junov@google.com4370aed2012-01-18 16:21:08 +0000972SkCanvas* SkCanvas::canvasForDrawIter() {
973 return this;
974}
975
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()
reed687fa1c2015-04-07 08:00:56 -07001111 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
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
brianosman52ede1d2016-06-20 08:25:02 -07001180 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace()));
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
robertphillips5139e502016-07-19 05:10:40 -07001259 SkAutoTUnref<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,
reedcd4051e2016-07-15 09:41:26 -07001265 preserveLCDText);
robertphillips5139e502016-07-19 05:10:40 -07001266 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1267 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001268 SkErrorInternals::SetError(kInternalError_SkError,
1269 "Unable to create device for layer.");
1270 return;
reed61f501f2015-04-29 08:34:00 -07001271 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001272 }
robertphillips5139e502016-07-19 05:10:40 -07001273 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001274
robertphillips5139e502016-07-19 05:10:40 -07001275 DeviceCM* layer = new DeviceCM(newDevice, 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) {
1282 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice,
1283 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 -08001382#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001383const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001384 SkPixmap pmap;
reed6ceeebd2016-03-09 14:26:26 -08001385 if (this->peekPixels(&pmap)) {
1386 if (info) {
1387 *info = pmap.info();
1388 }
1389 if (rowBytes) {
1390 *rowBytes = pmap.rowBytes();
1391 }
1392 return pmap.addr();
reed884e97c2015-05-26 11:31:54 -07001393 }
reed6ceeebd2016-03-09 14:26:26 -08001394 return nullptr;
1395}
1396#endif
1397
1398bool SkCanvas::peekPixels(SkPixmap* pmap) {
1399 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001400}
1401
reed884e97c2015-05-26 11:31:54 -07001402bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001403 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001404 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001405}
1406
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001407void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001408 SkPixmap pmap;
1409 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001410 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001411 }
1412 if (info) {
1413 *info = pmap.info();
1414 }
1415 if (rowBytes) {
1416 *rowBytes = pmap.rowBytes();
1417 }
1418 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001419 *origin = this->getTopDevice(false)->getOrigin();
1420 }
reed884e97c2015-05-26 11:31:54 -07001421 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001422}
1423
reed884e97c2015-05-26 11:31:54 -07001424bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001425 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001426 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001427}
1428
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001430
reed7503d602016-07-15 14:23:29 -07001431void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001432 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001433 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001434 paint = &tmp;
1435 }
reed@google.com4b226022011-01-11 18:32:13 +00001436
reed@google.com8926b162012-03-23 15:36:36 +00001437 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001438
reed@android.com8a1c16f2008-12-17 15:59:43 +00001439 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001440 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001441 paint = &looper.paint();
1442 SkImageFilter* filter = paint->getImageFilter();
1443 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
senorblancof35566e2016-04-18 10:32:02 -07001444 if (filter) {
reeda2217ef2016-07-20 06:04:34 -07001445 dstDev->drawSpecial(iter, srcDev->snapSpecial().get(), pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001446 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001447 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001448 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001449 }
reeda2217ef2016-07-20 06:04:34 -07001450
reed@google.com4e2b3d32011-04-07 14:18:59 +00001451 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001452}
1453
reed32704672015-12-16 08:27:10 -08001454/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001455
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001456void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001457 if (dx || dy) {
1458 this->checkForDeferredSave();
1459 fDeviceCMDirty = true;
1460 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001461
reedfe69b502016-09-12 06:31:48 -07001462 // Translate shouldn't affect the is-scale-translateness of the matrix.
1463 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001464
reedfe69b502016-09-12 06:31:48 -07001465 this->didTranslate(dx,dy);
1466 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001467}
1468
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001469void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001470 SkMatrix m;
1471 m.setScale(sx, sy);
1472 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001473}
1474
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001475void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001476 SkMatrix m;
1477 m.setRotate(degrees);
1478 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001479}
1480
bungeman7438bfc2016-07-12 15:01:19 -07001481void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1482 SkMatrix m;
1483 m.setRotate(degrees, px, py);
1484 this->concat(m);
1485}
1486
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001487void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001488 SkMatrix m;
1489 m.setSkew(sx, sy);
1490 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001491}
1492
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001493void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001494 if (matrix.isIdentity()) {
1495 return;
1496 }
1497
reed2ff1fce2014-12-11 07:07:37 -08001498 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001499 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001500 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001501 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001502 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001503}
1504
reed8c30a812016-04-20 16:36:51 -07001505void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001506 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001507 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001508 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001509}
1510
1511void SkCanvas::setMatrix(const SkMatrix& matrix) {
1512 this->checkForDeferredSave();
1513 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001514 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001515}
1516
reed@android.com8a1c16f2008-12-17 15:59:43 +00001517void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001518 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001519}
1520
vjiaoblack95302da2016-07-21 10:25:54 -07001521#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001522void SkCanvas::translateZ(SkScalar z) {
1523 this->checkForDeferredSave();
1524 this->fMCRec->fCurDrawDepth += z;
1525 this->didTranslateZ(z);
1526}
1527
1528SkScalar SkCanvas::getZ() const {
1529 return this->fMCRec->fCurDrawDepth;
1530}
1531
vjiaoblack95302da2016-07-21 10:25:54 -07001532void SkCanvas::setLights(sk_sp<SkLights> lights) {
1533 this->fLights = lights;
1534}
1535
1536sk_sp<SkLights> SkCanvas::getLights() const {
1537 return this->fLights;
1538}
1539#endif
1540
reed@android.com8a1c16f2008-12-17 15:59:43 +00001541//////////////////////////////////////////////////////////////////////////////
1542
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001543void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2d1afab2016-06-29 14:33:11 -07001544 if (!fAllowSoftClip) {
1545 doAA = false;
1546 }
1547
reed2ff1fce2014-12-11 07:07:37 -08001548 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001549 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1550 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001551}
1552
1553void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed74467162016-06-30 08:15:35 -07001554 const bool isScaleTrans = fMCRec->fMatrix.isScaleTranslate();
reedc64eff52015-11-21 12:39:45 -08001555 SkRect devR;
reed74467162016-06-30 08:15:35 -07001556 if (isScaleTrans) {
halcanaryc5769b22016-08-10 07:13:21 -07001557 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect);
reedc64eff52015-11-21 12:39:45 -08001558 }
bsalomonac8cabd2015-11-20 18:53:07 -08001559
reedc64eff52015-11-21 12:39:45 -08001560 if (SkRegion::kIntersect_Op == op &&
1561 kHard_ClipEdgeStyle == edgeStyle
reed74467162016-06-30 08:15:35 -07001562 && isScaleTrans)
reedc64eff52015-11-21 12:39:45 -08001563 {
1564 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1565#if 0
1566 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1567 rect.left(), rect.top(), rect.right(), rect.bottom());
1568#endif
1569 return;
1570 }
1571 }
1572
1573 AutoValidateClip avc(this);
1574
1575 fDeviceCMDirty = true;
reedc64eff52015-11-21 12:39:45 -08001576
reed74467162016-06-30 08:15:35 -07001577 if (isScaleTrans) {
reedc64eff52015-11-21 12:39:45 -08001578 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1579 fClipStack->clipDevRect(devR, op, isAA);
senorblancoafc7cce2016-02-02 18:44:15 -08001580 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001581 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001582 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001583 // and clip against that, since it can handle any matrix. However, to
1584 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1585 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001586 SkPath path;
1587
1588 path.addRect(rect);
bsalomonbdc335f2016-08-22 13:42:17 -07001589 path.setIsVolatile(true);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001590 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001591 }
msarettfbfa2582016-08-12 08:29:08 -07001592
1593 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001594}
1595
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001596void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001597 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001598 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001599 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001600 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1601 } else {
1602 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001603 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001604}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001605
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001606void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001607 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001608 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001609 AutoValidateClip avc(this);
1610
1611 fDeviceCMDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001612 if (!fAllowSoftClip) {
1613 edgeStyle = kHard_ClipEdgeStyle;
1614 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001615
reed687fa1c2015-04-07 08:00:56 -07001616 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001617
senorblancoafc7cce2016-02-02 18:44:15 -08001618 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
robertphillips125f19a2015-11-23 09:00:05 -08001619 kSoft_ClipEdgeStyle == edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001620 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001621 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001622 }
1623
1624 SkPath path;
1625 path.addRRect(rrect);
bsalomonbdc335f2016-08-22 13:42:17 -07001626 path.setIsVolatile(true);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001627 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001628 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001629}
1630
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001631void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001632 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001633 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001634
1635 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1636 SkRect r;
1637 if (path.isRect(&r)) {
1638 this->onClipRect(r, op, edgeStyle);
1639 return;
1640 }
1641 SkRRect rrect;
1642 if (path.isOval(&r)) {
1643 rrect.setOval(r);
1644 this->onClipRRect(rrect, op, edgeStyle);
1645 return;
1646 }
1647 if (path.isRRect(&rrect)) {
1648 this->onClipRRect(rrect, op, edgeStyle);
1649 return;
1650 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001651 }
robertphillips39f05382015-11-24 09:30:12 -08001652
1653 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001654}
1655
1656void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001657 AutoValidateClip avc(this);
1658
reed@android.com8a1c16f2008-12-17 15:59:43 +00001659 fDeviceCMDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001660 if (!fAllowSoftClip) {
1661 edgeStyle = kHard_ClipEdgeStyle;
1662 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001663
1664 SkPath devPath;
bsalomonbdc335f2016-08-22 13:42:17 -07001665 if (fMCRec->fMatrix.isIdentity()) {
1666 devPath = path;
1667 } else {
1668 path.transform(fMCRec->fMatrix, &devPath);
1669 devPath.setIsVolatile(true);
1670 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001671
reed@google.comfe701122011-11-08 19:41:23 +00001672 // Check if the transfomation, or the original path itself
1673 // made us empty. Note this can also happen if we contained NaN
1674 // values. computing the bounds detects this, and will set our
1675 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1676 if (devPath.getBounds().isEmpty()) {
1677 // resetting the path will remove any NaN or other wanky values
1678 // that might upset our scan converter.
1679 devPath.reset();
1680 }
1681
reed@google.com5c3d1472011-02-22 19:12:23 +00001682 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001683 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001684
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001685 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001686 bool clipIsAA = getClipStack()->asPath(&devPath);
1687 if (clipIsAA) {
1688 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001689 }
fmalita1a481fe2015-02-04 07:39:34 -08001690
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001691 op = SkRegion::kReplace_Op;
1692 }
1693
senorblancoafc7cce2016-02-02 18:44:15 -08001694 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001695 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001696}
1697
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001698void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001699 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001700 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001701}
1702
1703void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001704 AutoValidateClip avc(this);
1705
reed@android.com8a1c16f2008-12-17 15:59:43 +00001706 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001707
reed@google.com5c3d1472011-02-22 19:12:23 +00001708 // todo: signal fClipStack that we have a region, and therefore (I guess)
1709 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001710 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001711
reed1f836ee2014-07-07 07:49:34 -07001712 fMCRec->fRasterClip.op(rgn, op);
msarettfbfa2582016-08-12 08:29:08 -07001713 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001714}
1715
reed@google.com819c9212011-02-23 18:56:55 +00001716#ifdef SK_DEBUG
1717void SkCanvas::validateClip() const {
1718 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001719 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001720 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001721 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001722 return;
1723 }
1724
reed@google.com819c9212011-02-23 18:56:55 +00001725 SkIRect ir;
1726 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001727 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001728
reed687fa1c2015-04-07 08:00:56 -07001729 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001730 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001731 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001732 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001733 case SkClipStack::Element::kRect_Type:
1734 element->getRect().round(&ir);
1735 tmpClip.op(ir, element->getOp());
1736 break;
1737 case SkClipStack::Element::kEmpty_Type:
1738 tmpClip.setEmpty();
1739 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001740 default: {
1741 SkPath path;
1742 element->asPath(&path);
senorblancoafc7cce2016-02-02 18:44:15 -08001743 tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001744 break;
1745 }
reed@google.com819c9212011-02-23 18:56:55 +00001746 }
1747 }
reed@google.com819c9212011-02-23 18:56:55 +00001748}
1749#endif
1750
reed@google.com90c07ea2012-04-13 13:50:27 +00001751void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001752 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001753 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001754
halcanary96fcdcc2015-08-27 07:41:13 -07001755 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001756 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001757 }
1758}
1759
reed@google.com5c3d1472011-02-22 19:12:23 +00001760///////////////////////////////////////////////////////////////////////////////
1761
reed@google.com754de5f2014-02-24 19:38:20 +00001762bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001763 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001764}
1765
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001766bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001767 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001768}
1769
msarettfbfa2582016-08-12 08:29:08 -07001770static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1771#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1772 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1773 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1774 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1775 return 0xF != _mm_movemask_ps(mask);
1776#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1777 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1778 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1779 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1780 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1781#else
1782 SkRect devRectAsRect;
1783 SkRect devClipAsRect;
1784 devRect.store(&devRectAsRect.fLeft);
1785 devClip.store(&devClipAsRect.fLeft);
1786 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1787#endif
1788}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001789
msarettfbfa2582016-08-12 08:29:08 -07001790// It's important for this function to not be inlined. Otherwise the compiler will share code
1791// between the fast path and the slow path, resulting in two slow paths.
1792static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1793 const SkMatrix& matrix) {
1794 SkRect deviceRect;
1795 matrix.mapRect(&deviceRect, src);
1796 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1797}
1798
1799bool SkCanvas::quickReject(const SkRect& src) const {
1800#ifdef SK_DEBUG
1801 // Verify that fDeviceClipBounds are set properly.
1802 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001803 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001804 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001805 } else {
msarettfbfa2582016-08-12 08:29:08 -07001806 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001807 }
msarettfbfa2582016-08-12 08:29:08 -07001808
msarett9637ea92016-08-18 14:03:30 -07001809 // Verify that fIsScaleTranslate is set properly.
1810 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001811#endif
1812
msarett9637ea92016-08-18 14:03:30 -07001813 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001814 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1815 }
1816
1817 // We inline the implementation of mapScaleTranslate() for the fast path.
1818 float sx = fMCRec->fMatrix.getScaleX();
1819 float sy = fMCRec->fMatrix.getScaleY();
1820 float tx = fMCRec->fMatrix.getTranslateX();
1821 float ty = fMCRec->fMatrix.getTranslateY();
1822 Sk4f scale(sx, sy, sx, sy);
1823 Sk4f trans(tx, ty, tx, ty);
1824
1825 // Apply matrix.
1826 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1827
1828 // Make sure left < right, top < bottom.
1829 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1830 Sk4f min = Sk4f::Min(ltrb, rblt);
1831 Sk4f max = Sk4f::Max(ltrb, rblt);
1832 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1833 // ARM this sequence generates the fastest (a single instruction).
1834 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1835
1836 // Check if the device rect is NaN or outside the clip.
1837 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001838}
1839
reed@google.com3b3e8952012-08-16 20:53:31 +00001840bool SkCanvas::quickReject(const SkPath& path) const {
1841 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001842}
1843
reed@google.com3b3e8952012-08-16 20:53:31 +00001844bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001845 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001846 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001847 return false;
1848 }
1849
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001850 SkMatrix inverse;
1851 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001852 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001853 if (bounds) {
1854 bounds->setEmpty();
1855 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001856 return false;
1857 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001858
bsalomon49f085d2014-09-05 13:34:00 -07001859 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001860 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001861 // adjust it outwards in case we are antialiasing
1862 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001863
reed@google.com8f4d2302013-12-17 16:44:46 +00001864 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1865 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001866 inverse.mapRect(bounds, r);
1867 }
1868 return true;
1869}
1870
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001871bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001872 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001873 if (clip.isEmpty()) {
1874 if (bounds) {
1875 bounds->setEmpty();
1876 }
1877 return false;
1878 }
1879
bsalomon49f085d2014-09-05 13:34:00 -07001880 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001881 *bounds = clip.getBounds();
1882 }
1883 return true;
1884}
1885
reed@android.com8a1c16f2008-12-17 15:59:43 +00001886const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001887 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001888}
1889
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001890const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001891 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001892}
1893
robertphillips175dd9b2016-04-28 14:32:04 -07001894GrDrawContext* SkCanvas::internal_private_accessTopLayerDrawContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001895 SkBaseDevice* dev = this->getTopDevice();
robertphillips175dd9b2016-04-28 14:32:04 -07001896 return dev ? dev->accessDrawContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001897}
1898
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001899GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001900 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001901 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001902}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001903
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001904void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1905 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001906 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001907 if (outer.isEmpty()) {
1908 return;
1909 }
1910 if (inner.isEmpty()) {
1911 this->drawRRect(outer, paint);
1912 return;
1913 }
1914
1915 // We don't have this method (yet), but technically this is what we should
1916 // be able to assert...
1917 // SkASSERT(outer.contains(inner));
1918 //
1919 // For now at least check for containment of bounds
1920 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1921
1922 this->onDrawDRRect(outer, inner, paint);
1923}
1924
reed41af9662015-01-05 07:49:08 -08001925// These need to stop being virtual -- clients need to override the onDraw... versions
1926
1927void SkCanvas::drawPaint(const SkPaint& paint) {
1928 this->onDrawPaint(paint);
1929}
1930
1931void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1932 this->onDrawRect(r, paint);
1933}
1934
msarettdca352e2016-08-26 06:37:45 -07001935void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1936 if (region.isEmpty()) {
1937 return;
1938 }
1939
1940 if (region.isRect()) {
1941 return this->drawIRect(region.getBounds(), paint);
1942 }
1943
1944 this->onDrawRegion(region, paint);
1945}
1946
reed41af9662015-01-05 07:49:08 -08001947void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1948 this->onDrawOval(r, paint);
1949}
1950
1951void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1952 this->onDrawRRect(rrect, paint);
1953}
1954
1955void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1956 this->onDrawPoints(mode, count, pts, paint);
1957}
1958
1959void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1960 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1961 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1962 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1963 indices, indexCount, paint);
1964}
1965
1966void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1967 this->onDrawPath(path, paint);
1968}
1969
reeda85d4d02015-05-06 12:56:48 -07001970void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001971 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001972 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001973}
1974
reede47829b2015-08-06 10:02:53 -07001975void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1976 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001977 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001978 if (dst.isEmpty() || src.isEmpty()) {
1979 return;
1980 }
1981 this->onDrawImageRect(image, &src, dst, paint, constraint);
1982}
reed41af9662015-01-05 07:49:08 -08001983
reed84984ef2015-07-17 07:09:43 -07001984void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1985 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001986 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001987 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001988}
1989
reede47829b2015-08-06 10:02:53 -07001990void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1991 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001992 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001993 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1994 constraint);
1995}
reede47829b2015-08-06 10:02:53 -07001996
reed4c21dc52015-06-25 12:32:03 -07001997void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1998 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001999 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07002000 if (dst.isEmpty()) {
2001 return;
2002 }
msarett552bca92016-08-03 06:53:26 -07002003 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
2004 this->onDrawImageNine(image, center, dst, paint);
2005 } else {
reede47829b2015-08-06 10:02:53 -07002006 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002007 }
reed4c21dc52015-06-25 12:32:03 -07002008}
2009
msarett16882062016-08-16 09:31:08 -07002010void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2011 const SkPaint* paint) {
2012 RETURN_ON_NULL(image);
2013 if (dst.isEmpty()) {
2014 return;
2015 }
2016 if (SkLatticeIter::Valid(image->width(), image->height(), lattice)) {
2017 this->onDrawImageLattice(image, lattice, dst, paint);
2018 } else {
2019 this->drawImageRect(image, dst, paint);
2020 }
2021}
2022
reed41af9662015-01-05 07:49:08 -08002023void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002024 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002025 return;
2026 }
reed41af9662015-01-05 07:49:08 -08002027 this->onDrawBitmap(bitmap, dx, dy, paint);
2028}
2029
reede47829b2015-08-06 10:02:53 -07002030void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002031 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002032 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002033 return;
2034 }
reede47829b2015-08-06 10:02:53 -07002035 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002036}
2037
reed84984ef2015-07-17 07:09:43 -07002038void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2039 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002040 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002041}
2042
reede47829b2015-08-06 10:02:53 -07002043void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2044 SrcRectConstraint constraint) {
2045 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2046 constraint);
2047}
reede47829b2015-08-06 10:02:53 -07002048
reed41af9662015-01-05 07:49:08 -08002049void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2050 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002051 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002052 return;
2053 }
msarett552bca92016-08-03 06:53:26 -07002054 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2055 this->onDrawBitmapNine(bitmap, center, dst, paint);
2056 } else {
reeda5517e22015-07-14 10:54:12 -07002057 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002058 }
reed41af9662015-01-05 07:49:08 -08002059}
2060
msarettc573a402016-08-02 08:05:56 -07002061void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2062 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002063 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002064 return;
2065 }
msarett16882062016-08-16 09:31:08 -07002066 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), lattice)) {
2067 this->onDrawBitmapLattice(bitmap, lattice, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002068 } else {
msarett16882062016-08-16 09:31:08 -07002069 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002070 }
msarettc573a402016-08-02 08:05:56 -07002071}
2072
reed71c3c762015-06-24 10:29:17 -07002073void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2074 const SkColor colors[], int count, SkXfermode::Mode mode,
2075 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002076 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002077 if (count <= 0) {
2078 return;
2079 }
2080 SkASSERT(atlas);
2081 SkASSERT(xform);
2082 SkASSERT(tex);
2083 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2084}
2085
reedf70b5312016-03-04 16:36:20 -08002086void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2087 if (key) {
2088 this->onDrawAnnotation(rect, key, value);
2089 }
2090}
2091
reede47829b2015-08-06 10:02:53 -07002092void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2093 const SkPaint* paint, SrcRectConstraint constraint) {
2094 if (src) {
2095 this->drawImageRect(image, *src, dst, paint, constraint);
2096 } else {
2097 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2098 dst, paint, constraint);
2099 }
2100}
2101void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2102 const SkPaint* paint, SrcRectConstraint constraint) {
2103 if (src) {
2104 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2105 } else {
2106 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2107 dst, paint, constraint);
2108 }
2109}
2110
tomhudsoncb3bd182016-05-18 07:24:16 -07002111void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2112 SkIRect layer_bounds = this->getTopLayerBounds();
2113 if (matrix) {
2114 *matrix = this->getTotalMatrix();
2115 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2116 }
2117 if (clip_bounds) {
2118 this->getClipDeviceBounds(clip_bounds);
2119 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2120 }
2121}
2122
reed@android.com8a1c16f2008-12-17 15:59:43 +00002123//////////////////////////////////////////////////////////////////////////////
2124// These are the virtual drawing methods
2125//////////////////////////////////////////////////////////////////////////////
2126
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002127void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002128 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002129 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2130 }
2131}
2132
reed41af9662015-01-05 07:49:08 -08002133void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002134 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002135 this->internalDrawPaint(paint);
2136}
2137
2138void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002139 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002140
2141 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002142 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002143 }
2144
reed@google.com4e2b3d32011-04-07 14:18:59 +00002145 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002146}
2147
reed41af9662015-01-05 07:49:08 -08002148void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2149 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002150 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151 if ((long)count <= 0) {
2152 return;
2153 }
2154
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002155 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002156 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002157 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002158 // special-case 2 points (common for drawing a single line)
2159 if (2 == count) {
2160 r.set(pts[0], pts[1]);
2161 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002162 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002163 }
senorblanco87e066e2015-10-28 11:23:36 -07002164 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2165 return;
2166 }
2167 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002168 }
reed@google.coma584aed2012-05-16 14:06:02 +00002169
halcanary96fcdcc2015-08-27 07:41:13 -07002170 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002171
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002172 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002173
reed@android.com8a1c16f2008-12-17 15:59:43 +00002174 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002175 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002176 }
reed@google.com4b226022011-01-11 18:32:13 +00002177
reed@google.com4e2b3d32011-04-07 14:18:59 +00002178 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002179}
2180
reed4a167172016-08-18 17:15:25 -07002181static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2182 return ((intptr_t)paint.getImageFilter() |
2183#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2184 (intptr_t)canvas->getDrawFilter() |
2185#endif
2186 (intptr_t)paint.getLooper() ) != 0;
2187}
2188
reed41af9662015-01-05 07:49:08 -08002189void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002190 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002191 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002192 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002193 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002194 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2195 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2196 SkRect tmp(r);
2197 tmp.sort();
2198
senorblanco87e066e2015-10-28 11:23:36 -07002199 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2200 return;
2201 }
2202 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002203 }
reed@google.com4b226022011-01-11 18:32:13 +00002204
reed4a167172016-08-18 17:15:25 -07002205 if (needs_autodrawlooper(this, paint)) {
2206 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002207
reed4a167172016-08-18 17:15:25 -07002208 while (iter.next()) {
2209 iter.fDevice->drawRect(iter, r, looper.paint());
2210 }
2211
2212 LOOPER_END
2213 } else {
2214 this->predrawNotify(bounds, &paint, false);
2215 SkDrawIter iter(this);
2216 while (iter.next()) {
2217 iter.fDevice->drawRect(iter, r, paint);
2218 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002219 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002220}
2221
msarett44df6512016-08-25 13:54:30 -07002222void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2223 SkRect storage;
2224 SkRect regionRect = SkRect::Make(region.getBounds());
2225 const SkRect* bounds = nullptr;
2226 if (paint.canComputeFastBounds()) {
2227 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2228 return;
2229 }
2230 bounds = &regionRect;
2231 }
2232
2233 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2234
2235 while (iter.next()) {
2236 iter.fDevice->drawRegion(iter, region, looper.paint());
2237 }
2238
2239 LOOPER_END
2240}
2241
reed41af9662015-01-05 07:49:08 -08002242void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002243 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002244 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002245 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002246 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002247 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2248 return;
2249 }
2250 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002251 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002252
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002253 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002254
2255 while (iter.next()) {
2256 iter.fDevice->drawOval(iter, oval, looper.paint());
2257 }
2258
2259 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002260}
2261
bsalomonac3aa242016-08-19 11:25:19 -07002262void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2263 SkScalar sweepAngle, bool useCenter,
2264 const SkPaint& paint) {
2265 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2266 const SkRect* bounds = nullptr;
2267 if (paint.canComputeFastBounds()) {
2268 SkRect storage;
2269 // Note we're using the entire oval as the bounds.
2270 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2271 return;
2272 }
2273 bounds = &oval;
2274 }
2275
2276 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2277
2278 while (iter.next()) {
2279 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2280 }
2281
2282 LOOPER_END
2283}
2284
reed41af9662015-01-05 07:49:08 -08002285void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002286 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002287 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002288 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002289 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002290 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2291 return;
2292 }
2293 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002294 }
2295
2296 if (rrect.isRect()) {
2297 // call the non-virtual version
2298 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002299 return;
2300 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002301 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002302 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2303 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002304 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002305
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002306 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002307
2308 while (iter.next()) {
2309 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2310 }
2311
2312 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002313}
2314
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002315void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2316 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002317 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002318 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002319 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002320 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2321 return;
2322 }
2323 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002324 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002325
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002326 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002327
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002328 while (iter.next()) {
2329 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2330 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002331
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002332 LOOPER_END
2333}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002334
reed41af9662015-01-05 07:49:08 -08002335void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002336 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002337 if (!path.isFinite()) {
2338 return;
2339 }
2340
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002341 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002342 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002343 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002344 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002345 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2346 return;
2347 }
2348 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002349 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002350
2351 const SkRect& r = path.getBounds();
2352 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002353 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002354 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002355 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002356 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002357 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002358
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002359 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002360
2361 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002362 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002363 }
2364
reed@google.com4e2b3d32011-04-07 14:18:59 +00002365 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002366}
2367
reed262a71b2015-12-05 13:07:27 -08002368bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002369 if (!paint.getImageFilter()) {
2370 return false;
2371 }
2372
2373 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002374 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002375 return false;
2376 }
2377
2378 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2379 // Once we can filter and the filter will return a result larger than itself, we should be
2380 // able to remove this constraint.
2381 // skbug.com/4526
2382 //
2383 SkPoint pt;
2384 ctm.mapXY(x, y, &pt);
2385 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2386 return ir.contains(fMCRec->fRasterClip.getBounds());
2387}
2388
reeda85d4d02015-05-06 12:56:48 -07002389void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002390 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002391 SkRect bounds = SkRect::MakeXYWH(x, y,
2392 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002393 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002394 SkRect tmp = bounds;
2395 if (paint) {
2396 paint->computeFastBounds(tmp, &tmp);
2397 }
2398 if (this->quickReject(tmp)) {
2399 return;
2400 }
reeda85d4d02015-05-06 12:56:48 -07002401 }
halcanary9d524f22016-03-29 09:03:52 -07002402
reeda85d4d02015-05-06 12:56:48 -07002403 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002404 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002405 paint = lazy.init();
2406 }
reed262a71b2015-12-05 13:07:27 -08002407
reeda2217ef2016-07-20 06:04:34 -07002408 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002409 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2410 *paint);
2411 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002412 special = this->getDevice()->makeSpecial(image);
2413 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002414 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002415 }
2416 }
2417
reed262a71b2015-12-05 13:07:27 -08002418 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2419
reeda85d4d02015-05-06 12:56:48 -07002420 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002421 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002422 if (special) {
2423 SkPoint pt;
2424 iter.fMatrix->mapXY(x, y, &pt);
2425 iter.fDevice->drawSpecial(iter, special.get(),
2426 SkScalarRoundToInt(pt.fX),
2427 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002428 } else {
2429 iter.fDevice->drawImage(iter, image, x, y, pnt);
2430 }
reeda85d4d02015-05-06 12:56:48 -07002431 }
halcanary9d524f22016-03-29 09:03:52 -07002432
reeda85d4d02015-05-06 12:56:48 -07002433 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002434}
2435
reed41af9662015-01-05 07:49:08 -08002436void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002437 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002438 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002439 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002440 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002441 if (paint) {
2442 paint->computeFastBounds(dst, &storage);
2443 }
2444 if (this->quickReject(storage)) {
2445 return;
2446 }
reeda85d4d02015-05-06 12:56:48 -07002447 }
2448 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002449 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002450 paint = lazy.init();
2451 }
halcanary9d524f22016-03-29 09:03:52 -07002452
senorblancoc41e7e12015-12-07 12:51:30 -08002453 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002454 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002455
reeda85d4d02015-05-06 12:56:48 -07002456 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002457 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002458 }
halcanary9d524f22016-03-29 09:03:52 -07002459
reeda85d4d02015-05-06 12:56:48 -07002460 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002461}
2462
reed41af9662015-01-05 07:49:08 -08002463void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002464 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002465 SkDEBUGCODE(bitmap.validate();)
2466
reed33366972015-10-08 09:22:02 -07002467 if (bitmap.drawsNothing()) {
2468 return;
2469 }
2470
2471 SkLazyPaint lazy;
2472 if (nullptr == paint) {
2473 paint = lazy.init();
2474 }
2475
2476 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2477
2478 SkRect storage;
2479 const SkRect* bounds = nullptr;
2480 if (paint->canComputeFastBounds()) {
2481 bitmap.getBounds(&storage);
2482 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002483 SkRect tmp = storage;
2484 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2485 return;
2486 }
2487 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488 }
reed@google.com4b226022011-01-11 18:32:13 +00002489
reeda2217ef2016-07-20 06:04:34 -07002490 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002491 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2492 *paint);
2493 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002494 special = this->getDevice()->makeSpecial(bitmap);
2495 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002496 drawAsSprite = false;
2497 }
2498 }
2499
reed262a71b2015-12-05 13:07:27 -08002500 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002501
2502 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002503 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002504 if (special) {
reed262a71b2015-12-05 13:07:27 -08002505 SkPoint pt;
2506 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002507 iter.fDevice->drawSpecial(iter, special.get(),
2508 SkScalarRoundToInt(pt.fX),
2509 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002510 } else {
2511 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2512 }
reed33366972015-10-08 09:22:02 -07002513 }
msarettfbfa2582016-08-12 08:29:08 -07002514
reed33366972015-10-08 09:22:02 -07002515 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002516}
2517
reed@google.com9987ec32011-09-07 11:57:52 +00002518// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002519void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002520 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002521 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002522 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002523 return;
2524 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002525
halcanary96fcdcc2015-08-27 07:41:13 -07002526 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002527 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002528 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2529 return;
2530 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002531 }
reed@google.com3d608122011-11-21 15:16:16 +00002532
reed@google.com33535f32012-09-25 15:37:50 +00002533 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002534 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002535 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002536 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002537
senorblancoc41e7e12015-12-07 12:51:30 -08002538 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002539 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002540
reed@google.com33535f32012-09-25 15:37:50 +00002541 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002542 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002543 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002544
reed@google.com33535f32012-09-25 15:37:50 +00002545 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002546}
2547
reed41af9662015-01-05 07:49:08 -08002548void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002549 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002550 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002551 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002552 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002553}
2554
reed4c21dc52015-06-25 12:32:03 -07002555void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2556 const SkPaint* paint) {
2557 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002558
halcanary96fcdcc2015-08-27 07:41:13 -07002559 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002560 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002561 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2562 return;
2563 }
reed@google.com3d608122011-11-21 15:16:16 +00002564 }
halcanary9d524f22016-03-29 09:03:52 -07002565
reed4c21dc52015-06-25 12:32:03 -07002566 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002567 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002568 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002569 }
halcanary9d524f22016-03-29 09:03:52 -07002570
senorblancoc41e7e12015-12-07 12:51:30 -08002571 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002572
reed4c21dc52015-06-25 12:32:03 -07002573 while (iter.next()) {
2574 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002575 }
halcanary9d524f22016-03-29 09:03:52 -07002576
reed4c21dc52015-06-25 12:32:03 -07002577 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002578}
2579
reed41af9662015-01-05 07:49:08 -08002580void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2581 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002582 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002583 SkDEBUGCODE(bitmap.validate();)
2584
halcanary96fcdcc2015-08-27 07:41:13 -07002585 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002586 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002587 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2588 return;
2589 }
reed4c21dc52015-06-25 12:32:03 -07002590 }
halcanary9d524f22016-03-29 09:03:52 -07002591
reed4c21dc52015-06-25 12:32:03 -07002592 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002593 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002594 paint = lazy.init();
2595 }
halcanary9d524f22016-03-29 09:03:52 -07002596
senorblancoc41e7e12015-12-07 12:51:30 -08002597 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002598
reed4c21dc52015-06-25 12:32:03 -07002599 while (iter.next()) {
2600 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2601 }
halcanary9d524f22016-03-29 09:03:52 -07002602
reed4c21dc52015-06-25 12:32:03 -07002603 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002604}
2605
msarett16882062016-08-16 09:31:08 -07002606void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2607 const SkPaint* paint) {
2608 if (nullptr == paint || paint->canComputeFastBounds()) {
2609 SkRect storage;
2610 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2611 return;
2612 }
2613 }
2614
2615 SkLazyPaint lazy;
2616 if (nullptr == paint) {
2617 paint = lazy.init();
2618 }
2619
2620 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2621
2622 while (iter.next()) {
2623 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2624 }
2625
2626 LOOPER_END
2627}
2628
2629void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2630 const SkRect& dst, const SkPaint* paint) {
2631 if (nullptr == paint || paint->canComputeFastBounds()) {
2632 SkRect storage;
2633 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2634 return;
2635 }
2636 }
2637
2638 SkLazyPaint lazy;
2639 if (nullptr == paint) {
2640 paint = lazy.init();
2641 }
2642
2643 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2644
2645 while (iter.next()) {
2646 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2647 }
2648
2649 LOOPER_END
2650}
2651
reed@google.comf67e4cf2011-03-15 20:56:58 +00002652class SkDeviceFilteredPaint {
2653public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002654 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002655 uint32_t filteredFlags = device->filterTextFlags(paint);
2656 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002657 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002658 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002659 fPaint = newPaint;
2660 } else {
2661 fPaint = &paint;
2662 }
2663 }
2664
reed@google.comf67e4cf2011-03-15 20:56:58 +00002665 const SkPaint& paint() const { return *fPaint; }
2666
2667private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002668 const SkPaint* fPaint;
2669 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002670};
2671
bungeman@google.com52c748b2011-08-22 21:30:43 +00002672void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2673 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002674 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002675 draw.fDevice->drawRect(draw, r, paint);
2676 } else {
2677 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002678 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002679 draw.fDevice->drawRect(draw, r, p);
2680 }
2681}
2682
2683void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2684 const char text[], size_t byteLength,
2685 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002686 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002687
2688 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002689 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002690 draw.fRC->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002691 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002692 return;
2693 }
2694
2695 SkScalar width = 0;
2696 SkPoint start;
2697
2698 start.set(0, 0); // to avoid warning
2699 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2700 SkPaint::kStrikeThruText_Flag)) {
2701 width = paint.measureText(text, byteLength);
2702
2703 SkScalar offsetX = 0;
2704 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2705 offsetX = SkScalarHalf(width);
2706 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2707 offsetX = width;
2708 }
2709 start.set(x - offsetX, y);
2710 }
2711
2712 if (0 == width) {
2713 return;
2714 }
2715
2716 uint32_t flags = paint.getFlags();
2717
2718 if (flags & (SkPaint::kUnderlineText_Flag |
2719 SkPaint::kStrikeThruText_Flag)) {
2720 SkScalar textSize = paint.getTextSize();
2721 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2722 SkRect r;
2723
2724 r.fLeft = start.fX;
2725 r.fRight = start.fX + width;
2726
2727 if (flags & SkPaint::kUnderlineText_Flag) {
2728 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2729 start.fY);
2730 r.fTop = offset;
2731 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002732 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002733 }
2734 if (flags & SkPaint::kStrikeThruText_Flag) {
2735 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2736 start.fY);
2737 r.fTop = offset;
2738 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002739 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002740 }
2741 }
2742}
2743
reed@google.come0d9ce82014-04-23 04:00:17 +00002744void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2745 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002746 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002747
2748 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002749 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002750 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002751 DrawTextDecorations(iter, dfp.paint(),
2752 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753 }
2754
reed@google.com4e2b3d32011-04-07 14:18:59 +00002755 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002756}
2757
reed@google.come0d9ce82014-04-23 04:00:17 +00002758void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2759 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002760 SkPoint textOffset = SkPoint::Make(0, 0);
2761
halcanary96fcdcc2015-08-27 07:41:13 -07002762 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002763
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002765 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002766 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002767 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002768 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002769
reed@google.com4e2b3d32011-04-07 14:18:59 +00002770 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002771}
2772
reed@google.come0d9ce82014-04-23 04:00:17 +00002773void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2774 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002775
2776 SkPoint textOffset = SkPoint::Make(0, constY);
2777
halcanary96fcdcc2015-08-27 07:41:13 -07002778 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002779
reed@android.com8a1c16f2008-12-17 15:59:43 +00002780 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002781 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002782 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002783 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002785
reed@google.com4e2b3d32011-04-07 14:18:59 +00002786 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002787}
2788
reed@google.come0d9ce82014-04-23 04:00:17 +00002789void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2790 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002791 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002792
reed@android.com8a1c16f2008-12-17 15:59:43 +00002793 while (iter.next()) {
2794 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002795 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002797
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002798 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002799}
2800
reed45561a02016-07-07 12:47:17 -07002801void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2802 const SkRect* cullRect, const SkPaint& paint) {
2803 if (cullRect && this->quickReject(*cullRect)) {
2804 return;
2805 }
2806
2807 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2808
2809 while (iter.next()) {
2810 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2811 }
2812
2813 LOOPER_END
2814}
2815
fmalita00d5c2c2014-08-21 08:53:26 -07002816void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2817 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002818
fmalita85d5eb92015-03-04 11:20:12 -08002819 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002820 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002821 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002822 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002823 SkRect tmp;
2824 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2825 return;
2826 }
2827 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002828 }
2829
fmalita024f9962015-03-03 19:08:17 -08002830 // We cannot filter in the looper as we normally do, because the paint is
2831 // incomplete at this point (text-related attributes are embedded within blob run paints).
2832 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002833 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002834
fmalita85d5eb92015-03-04 11:20:12 -08002835 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002836
fmalitaaa1b9122014-08-28 14:32:24 -07002837 while (iter.next()) {
2838 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002839 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002840 }
2841
fmalitaaa1b9122014-08-28 14:32:24 -07002842 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002843
2844 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002845}
2846
reed@google.come0d9ce82014-04-23 04:00:17 +00002847// These will become non-virtual, so they always call the (virtual) onDraw... method
2848void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2849 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002850 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002851 if (byteLength) {
2852 this->onDrawText(text, byteLength, x, y, paint);
2853 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002854}
2855void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2856 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002857 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002858 if (byteLength) {
2859 this->onDrawPosText(text, byteLength, pos, paint);
2860 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002861}
2862void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2863 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002864 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002865 if (byteLength) {
2866 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2867 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002868}
2869void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2870 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002871 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002872 if (byteLength) {
2873 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2874 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002875}
reed45561a02016-07-07 12:47:17 -07002876void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2877 const SkRect* cullRect, const SkPaint& paint) {
2878 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2879 if (byteLength) {
2880 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2881 }
2882}
fmalita00d5c2c2014-08-21 08:53:26 -07002883void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2884 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002885 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002886 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002887 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002888}
reed@google.come0d9ce82014-04-23 04:00:17 +00002889
reed41af9662015-01-05 07:49:08 -08002890void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2891 const SkPoint verts[], const SkPoint texs[],
2892 const SkColor colors[], SkXfermode* xmode,
2893 const uint16_t indices[], int indexCount,
2894 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002895 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002896 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002897
reed@android.com8a1c16f2008-12-17 15:59:43 +00002898 while (iter.next()) {
2899 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002900 colors, xmode, indices, indexCount,
2901 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002902 }
reed@google.com4b226022011-01-11 18:32:13 +00002903
reed@google.com4e2b3d32011-04-07 14:18:59 +00002904 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002905}
2906
dandovb3c9d1c2014-08-12 08:34:29 -07002907void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2908 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002909 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002910 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002911 return;
2912 }
mtklein6cfa73a2014-08-13 13:33:49 -07002913
dandovecfff212014-08-04 10:02:00 -07002914 // Since a patch is always within the convex hull of the control points, we discard it when its
2915 // bounding rectangle is completely outside the current clip.
2916 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002917 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002918 if (this->quickReject(bounds)) {
2919 return;
2920 }
mtklein6cfa73a2014-08-13 13:33:49 -07002921
dandovb3c9d1c2014-08-12 08:34:29 -07002922 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2923}
2924
2925void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2926 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2927
halcanary96fcdcc2015-08-27 07:41:13 -07002928 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002929
dandovecfff212014-08-04 10:02:00 -07002930 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002931 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002932 }
mtklein6cfa73a2014-08-13 13:33:49 -07002933
dandovecfff212014-08-04 10:02:00 -07002934 LOOPER_END
2935}
2936
reeda8db7282015-07-07 10:22:31 -07002937void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002938 RETURN_ON_NULL(dr);
2939 if (x || y) {
2940 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2941 this->onDrawDrawable(dr, &matrix);
2942 } else {
2943 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002944 }
2945}
2946
reeda8db7282015-07-07 10:22:31 -07002947void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002948 RETURN_ON_NULL(dr);
2949 if (matrix && matrix->isIdentity()) {
2950 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002951 }
reede3b38ce2016-01-08 09:18:44 -08002952 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002953}
2954
2955void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2956 SkRect bounds = dr->getBounds();
2957 if (matrix) {
2958 matrix->mapRect(&bounds);
2959 }
2960 if (this->quickReject(bounds)) {
2961 return;
2962 }
2963 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002964}
2965
reed71c3c762015-06-24 10:29:17 -07002966void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2967 const SkColor colors[], int count, SkXfermode::Mode mode,
2968 const SkRect* cull, const SkPaint* paint) {
2969 if (cull && this->quickReject(*cull)) {
2970 return;
2971 }
2972
2973 SkPaint pnt;
2974 if (paint) {
2975 pnt = *paint;
2976 }
halcanary9d524f22016-03-29 09:03:52 -07002977
halcanary96fcdcc2015-08-27 07:41:13 -07002978 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002979 while (iter.next()) {
2980 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2981 }
2982 LOOPER_END
2983}
2984
reedf70b5312016-03-04 16:36:20 -08002985void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2986 SkASSERT(key);
2987
2988 SkPaint paint;
2989 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2990 while (iter.next()) {
2991 iter.fDevice->drawAnnotation(iter, rect, key, value);
2992 }
2993 LOOPER_END
2994}
2995
reed@android.com8a1c16f2008-12-17 15:59:43 +00002996//////////////////////////////////////////////////////////////////////////////
2997// These methods are NOT virtual, and therefore must call back into virtual
2998// methods, rather than actually drawing themselves.
2999//////////////////////////////////////////////////////////////////////////////
3000
3001void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00003002 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003003 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003004 SkPaint paint;
3005
3006 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00003007 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003008 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003009 }
3010 this->drawPaint(paint);
3011}
3012
reed@android.com845fdac2009-06-23 03:01:32 +00003013void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003014 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003015 SkPaint paint;
3016
3017 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00003018 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003019 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003020 }
3021 this->drawPaint(paint);
3022}
3023
3024void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003025 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003026 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00003027
reed@android.com8a1c16f2008-12-17 15:59:43 +00003028 pt.set(x, y);
3029 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3030}
3031
3032void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08003033 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003034 SkPoint pt;
3035 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00003036
reed@android.com8a1c16f2008-12-17 15:59:43 +00003037 pt.set(x, y);
3038 paint.setColor(color);
3039 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3040}
3041
3042void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
3043 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003044 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003045 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003046
reed@android.com8a1c16f2008-12-17 15:59:43 +00003047 pts[0].set(x0, y0);
3048 pts[1].set(x1, y1);
3049 this->drawPoints(kLines_PointMode, 2, pts, paint);
3050}
3051
3052void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3053 SkScalar right, SkScalar bottom,
3054 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003055 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003056 SkRect r;
3057
3058 r.set(left, top, right, bottom);
3059 this->drawRect(r, paint);
3060}
3061
3062void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3063 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003064 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003065 if (radius < 0) {
3066 radius = 0;
3067 }
3068
3069 SkRect r;
3070 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003071 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003072}
3073
3074void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3075 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003076 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003077 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003078 SkRRect rrect;
3079 rrect.setRectXY(r, rx, ry);
3080 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003081 } else {
3082 this->drawRect(r, paint);
3083 }
3084}
3085
reed@android.com8a1c16f2008-12-17 15:59:43 +00003086void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3087 SkScalar sweepAngle, bool useCenter,
3088 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003089 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003090 if (oval.isEmpty() || !sweepAngle) {
3091 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003092 }
bsalomon21af9ca2016-08-25 12:29:23 -07003093 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003094}
3095
3096void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3097 const SkPath& path, SkScalar hOffset,
3098 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003099 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003100 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003101
reed@android.com8a1c16f2008-12-17 15:59:43 +00003102 matrix.setTranslate(hOffset, vOffset);
3103 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3104}
3105
reed@android.comf76bacf2009-05-13 14:00:33 +00003106///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003107
3108/**
3109 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3110 * against the playback cost of recursing into the subpicture to get at its actual ops.
3111 *
3112 * For now we pick a conservatively small value, though measurement (and other heuristics like
3113 * the type of ops contained) may justify changing this value.
3114 */
3115#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003116
reedd5fa1a42014-08-09 11:08:05 -07003117void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003118 RETURN_ON_NULL(picture);
3119
reed1c2c4412015-04-30 13:09:24 -07003120 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003121 if (matrix && matrix->isIdentity()) {
3122 matrix = nullptr;
3123 }
3124 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3125 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3126 picture->playback(this);
3127 } else {
3128 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003129 }
3130}
robertphillips9b14f262014-06-04 05:40:44 -07003131
reedd5fa1a42014-08-09 11:08:05 -07003132void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3133 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003134 if (!paint || paint->canComputeFastBounds()) {
3135 SkRect bounds = picture->cullRect();
3136 if (paint) {
3137 paint->computeFastBounds(bounds, &bounds);
3138 }
3139 if (matrix) {
3140 matrix->mapRect(&bounds);
3141 }
3142 if (this->quickReject(bounds)) {
3143 return;
3144 }
3145 }
3146
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003147 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003148 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003149}
3150
vjiaoblack95302da2016-07-21 10:25:54 -07003151#ifdef SK_EXPERIMENTAL_SHADOWING
3152void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3153 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003154 const SkPaint* paint,
3155 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003156 RETURN_ON_NULL(picture);
3157
3158 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3159
vjiaoblacke6f5d562016-08-25 06:30:23 -07003160 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003161}
3162
3163void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3164 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003165 const SkPaint* paint,
3166 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003167 if (!paint || paint->canComputeFastBounds()) {
3168 SkRect bounds = picture->cullRect();
3169 if (paint) {
3170 paint->computeFastBounds(bounds, &bounds);
3171 }
3172 if (matrix) {
3173 matrix->mapRect(&bounds);
3174 }
3175 if (this->quickReject(bounds)) {
3176 return;
3177 }
3178 }
3179
3180 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3181
vjiaoblacke6f5d562016-08-25 06:30:23 -07003182 sk_sp<SkImage> povDepthMap;
3183 sk_sp<SkImage> diffuseMap;
3184
vjiaoblack904527d2016-08-09 09:32:09 -07003185 // povDepthMap
3186 {
3187 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003188 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3189 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003190 sk_sp<SkLights> povLight = builder.finish();
3191
3192 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3193 picture->cullRect().height(),
3194 kBGRA_8888_SkColorType,
3195 kOpaque_SkAlphaType);
3196
3197 // Create a new surface (that matches the backend of canvas)
3198 // to create the povDepthMap
3199 sk_sp<SkSurface> surf(this->makeSurface(info));
3200
3201 // Wrap another SPFCanvas around the surface
3202 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3203 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3204
3205 // set the depth map canvas to have the light as the user's POV
3206 depthMapCanvas->setLights(std::move(povLight));
3207
3208 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003209 povDepthMap = surf->makeImageSnapshot();
3210 }
3211
3212 // diffuseMap
3213 {
3214 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3215 picture->cullRect().height(),
3216 kBGRA_8888_SkColorType,
3217 kOpaque_SkAlphaType);
3218
3219 sk_sp<SkSurface> surf(this->makeSurface(info));
3220 surf->getCanvas()->drawPicture(picture);
3221
3222 diffuseMap = surf->makeImageSnapshot();
3223 }
vjiaoblack904527d2016-08-09 09:32:09 -07003224
3225 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3226 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003227 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3228 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003229
3230 // TODO: pass the depth to the shader in vertices, or uniforms
3231 // so we don't have to render depth and color separately
3232 for (int i = 0; i < fLights->numLights(); ++i) {
3233 // skip over ambient lights; they don't cast shadows
3234 // lights that have shadow maps do not need updating (because lights are immutable)
3235 sk_sp<SkImage> depthMap;
3236 SkISize shMapSize;
3237
3238 if (fLights->light(i).getShadowMap() != nullptr) {
3239 continue;
3240 }
3241
3242 if (fLights->light(i).isRadial()) {
3243 shMapSize.fHeight = 1;
3244 shMapSize.fWidth = (int) picture->cullRect().width();
3245
3246 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3247 kBGRA_8888_SkColorType,
3248 kOpaque_SkAlphaType);
3249
3250 // Create new surface (that matches the backend of canvas)
3251 // for each shadow map
3252 sk_sp<SkSurface> surf(this->makeSurface(info));
3253
3254 // Wrap another SPFCanvas around the surface
3255 SkCanvas* depthMapCanvas = surf->getCanvas();
3256
3257 SkLights::Builder builder;
3258 builder.add(fLights->light(i));
3259 sk_sp<SkLights> curLight = builder.finish();
3260
3261 sk_sp<SkShader> shadowMapShader;
3262 shadowMapShader = SkRadialShadowMapShader::Make(
3263 povDepthShader, curLight,
3264 (int) picture->cullRect().width(),
3265 (int) picture->cullRect().height());
3266
3267 SkPaint shadowMapPaint;
3268 shadowMapPaint.setShader(std::move(shadowMapShader));
3269
3270 depthMapCanvas->setLights(curLight);
3271
3272 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3273 diffuseMap->height()),
3274 shadowMapPaint);
3275
3276 depthMap = surf->makeImageSnapshot();
3277
3278 } else {
3279 // TODO: compute the correct size of the depth map from the light properties
3280 // TODO: maybe add a kDepth_8_SkColorType
3281 // TODO: find actual max depth of picture
3282 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3283 fLights->light(i), 255,
3284 (int) picture->cullRect().width(),
3285 (int) picture->cullRect().height());
3286
3287 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3288 kBGRA_8888_SkColorType,
3289 kOpaque_SkAlphaType);
3290
3291 // Create a new surface (that matches the backend of canvas)
3292 // for each shadow map
3293 sk_sp<SkSurface> surf(this->makeSurface(info));
3294
3295 // Wrap another SPFCanvas around the surface
3296 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3297 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3298 depthMapCanvas->setShadowParams(params);
3299
3300 // set the depth map canvas to have the light we're drawing.
3301 SkLights::Builder builder;
3302 builder.add(fLights->light(i));
3303 sk_sp<SkLights> curLight = builder.finish();
3304 depthMapCanvas->setLights(std::move(curLight));
3305
3306 depthMapCanvas->drawPicture(picture);
3307 depthMap = surf->makeImageSnapshot();
3308 }
3309
3310 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3311 fLights->light(i).setShadowMap(std::move(depthMap));
3312 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3313 // we blur the variance map
3314 SkPaint blurPaint;
3315 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3316 params.fShadowRadius, nullptr));
3317
3318 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3319 kBGRA_8888_SkColorType,
3320 kOpaque_SkAlphaType);
3321
3322 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3323
3324 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3325
3326 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3327 }
3328 }
3329
3330 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003331 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3332 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003333 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003334 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003335 diffuseMap->height(),
3336 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003337
3338 shadowPaint.setShader(shadowShader);
3339
3340 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003341}
3342#endif
3343
reed@android.com8a1c16f2008-12-17 15:59:43 +00003344///////////////////////////////////////////////////////////////////////////////
3345///////////////////////////////////////////////////////////////////////////////
3346
reed3aafe112016-08-18 12:45:34 -07003347SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003348 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003349
3350 SkASSERT(canvas);
3351
reed3aafe112016-08-18 12:45:34 -07003352 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003353 fDone = !fImpl->next();
3354}
3355
3356SkCanvas::LayerIter::~LayerIter() {
3357 fImpl->~SkDrawIter();
3358}
3359
3360void SkCanvas::LayerIter::next() {
3361 fDone = !fImpl->next();
3362}
3363
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003364SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003365 return fImpl->getDevice();
3366}
3367
3368const SkMatrix& SkCanvas::LayerIter::matrix() const {
3369 return fImpl->getMatrix();
3370}
3371
3372const SkPaint& SkCanvas::LayerIter::paint() const {
3373 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003374 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003375 paint = &fDefaultPaint;
3376 }
3377 return *paint;
3378}
3379
reed1e7f5e72016-04-27 07:49:17 -07003380const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003381int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3382int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003383
3384///////////////////////////////////////////////////////////////////////////////
3385
fmalitac3b589a2014-06-05 12:40:07 -07003386SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003387
3388///////////////////////////////////////////////////////////////////////////////
3389
3390static bool supported_for_raster_canvas(const SkImageInfo& info) {
3391 switch (info.alphaType()) {
3392 case kPremul_SkAlphaType:
3393 case kOpaque_SkAlphaType:
3394 break;
3395 default:
3396 return false;
3397 }
3398
3399 switch (info.colorType()) {
3400 case kAlpha_8_SkColorType:
3401 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003402 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003403 break;
3404 default:
3405 return false;
3406 }
3407
3408 return true;
3409}
3410
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003411SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3412 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003413 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003414 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003415
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003416 SkBitmap bitmap;
3417 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003418 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003419 }
halcanary385fe4d2015-08-26 13:07:48 -07003420 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003421}
reedd5fa1a42014-08-09 11:08:05 -07003422
3423///////////////////////////////////////////////////////////////////////////////
3424
3425SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003426 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003427 : fCanvas(canvas)
3428 , fSaveCount(canvas->getSaveCount())
3429{
bsalomon49f085d2014-09-05 13:34:00 -07003430 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003431 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003432 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003433 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003434 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003435 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003436 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003437 canvas->save();
3438 }
mtklein6cfa73a2014-08-13 13:33:49 -07003439
bsalomon49f085d2014-09-05 13:34:00 -07003440 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003441 canvas->concat(*matrix);
3442 }
3443}
3444
3445SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3446 fCanvas->restoreToCount(fSaveCount);
3447}
reede8f30622016-03-23 18:59:25 -07003448
3449#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3450SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
3451 return this->makeSurface(info, props).release();
3452}
3453#endif