blob: aa74a642a8454ef865f5a2a0f413fbd3b3e71f13 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
bungemand3ebb482015-08-05 13:57:49 -07008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070017#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080018#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070019#include "SkImageFilter.h"
20#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070021#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060022#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
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) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323 canvas->updateDeviceCMCache();
324
bungeman6bd52842016-10-27 09:30:08 -0700325 fClipStack = canvas->getClipStack();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000326 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700327
328 fMultiDeviceCS = nullptr;
329 if (fCurrLayer->fNext) {
bungeman6bd52842016-10-27 09:30:08 -0700330 fMultiDeviceCS = canvas->fClipStack.get();
reed02f9ed72016-09-06 09:06:18 -0700331 fMultiDeviceCS->save();
332 }
333 }
334
335 ~SkDrawIter() {
336 if (fMultiDeviceCS) {
337 fMultiDeviceCS->restore();
338 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 }
reed@google.com4b226022011-01-11 18:32:13 +0000340
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700342 if (fMultiDeviceCS && fDevice) {
343 // remove the previous device's bounds
reed73603f32016-09-20 08:42:38 -0700344 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), SkCanvas::kDifference_Op);
reed02f9ed72016-09-06 09:06:18 -0700345 }
346
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700348 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
349 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 }
351
reed@google.comf68c5e22012-02-24 16:38:58 +0000352 const DeviceCM* rec = fCurrLayer;
353 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354
355 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000356 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700358 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700359 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700360 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000362 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363
364 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700365 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000366
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367 return true;
368 }
369 return false;
370 }
reed@google.com4b226022011-01-11 18:32:13 +0000371
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000372 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700373 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000374 int getX() const { return fDevice->getOrigin().x(); }
375 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000378
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380 const DeviceCM* fCurrLayer;
381 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700382 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383
384 typedef SkDraw INHERITED;
385};
386
387/////////////////////////////////////////////////////////////////////////////
388
reeddbc3cef2015-04-29 12:18:57 -0700389static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
390 return lazy->isValid() ? lazy->get() : lazy->set(orig);
391}
392
393/**
394 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700395 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700396 */
reedd053ce92016-03-22 10:17:23 -0700397static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700398 SkImageFilter* imgf = paint.getImageFilter();
399 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700400 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700401 }
402
reedd053ce92016-03-22 10:17:23 -0700403 SkColorFilter* imgCFPtr;
404 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700405 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700406 }
reedd053ce92016-03-22 10:17:23 -0700407 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700408
409 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700410 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700411 // there is no existing paint colorfilter, so we can just return the imagefilter's
412 return imgCF;
413 }
414
415 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
416 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700417 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700418}
419
senorblanco87e066e2015-10-28 11:23:36 -0700420/**
421 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
422 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
423 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
424 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
425 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
426 * conservative "effective" bounds based on the settings in the paint... with one exception. This
427 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
428 * deliberately ignored.
429 */
430static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
431 const SkRect& rawBounds,
432 SkRect* storage) {
433 SkPaint tmpUnfiltered(paint);
434 tmpUnfiltered.setImageFilter(nullptr);
435 if (tmpUnfiltered.canComputeFastBounds()) {
436 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
437 } else {
438 return rawBounds;
439 }
440}
441
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442class AutoDrawLooper {
443public:
senorblanco87e066e2015-10-28 11:23:36 -0700444 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
445 // paint. It's used to determine the size of the offscreen layer for filters.
446 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700447 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700448 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000449 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800450#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000451 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800452#else
453 fFilter = nullptr;
454#endif
reed4a8126e2014-09-22 07:29:03 -0700455 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000456 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700457 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000458 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000459
reedd053ce92016-03-22 10:17:23 -0700460 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700461 if (simplifiedCF) {
462 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700463 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700464 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700465 fPaint = paint;
466 }
467
468 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700469 /**
470 * We implement ImageFilters for a given draw by creating a layer, then applying the
471 * imagefilter to the pixels of that layer (its backing surface/image), and then
472 * we call restore() to xfer that layer to the main canvas.
473 *
474 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
475 * 2. Generate the src pixels:
476 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
477 * return (fPaint). We then draw the primitive (using srcover) into a cleared
478 * buffer/surface.
479 * 3. Restore the layer created in #1
480 * The imagefilter is passed the buffer/surface from the layer (now filled with the
481 * src pixels of the primitive). It returns a new "filtered" buffer, which we
482 * draw onto the previous layer using the xfermode from the original paint.
483 */
reed@google.com8926b162012-03-23 15:36:36 +0000484 SkPaint tmp;
Mike Reed5e257172016-11-01 11:22:05 -0400485 tmp.setImageFilter(sk_ref_sp(fPaint->getImageFilter()));
reed374772b2016-10-05 17:33:02 -0700486 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700487 SkRect storage;
488 if (rawBounds) {
489 // Make rawBounds include all paint outsets except for those due to image filters.
490 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
491 }
reedbfd5f172016-01-07 11:28:08 -0800492 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700493 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700494 fTempLayerForImageFilter = true;
495 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000496 }
497
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000498 if (SkDrawLooper* looper = paint.getLooper()) {
herbbf6d80a2016-11-15 06:26:56 -0800499 fLooperContext = fLooperContextAllocator.createWithIniter(
500 looper->contextSize(),
501 [&](void* buffer) {
502 return looper->createContext(canvas, buffer);
503 });
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);
reed374772b2016-10-05 17:33:02 -0700562 paint->setBlendMode(SkBlendMode::kSrcOver);
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.com45a75fb2013-04-25 13:34:40 +0000657 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700658 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800659 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700660 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700661#ifdef SK_EXPERIMENTAL_SHADOWING
662 fLights = nullptr;
663#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664
halcanary385fe4d2015-08-26 13:07:48 -0700665 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700666
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700668 new (fMCRec) MCRec(fConservativeRasterClip);
msarett9637ea92016-08-18 14:03:30 -0700669 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670
reeda499f902015-05-01 09:34:31 -0700671 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
672 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700673 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700674 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700675
reed@android.com8a1c16f2008-12-17 15:59:43 +0000676 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677
halcanary96fcdcc2015-08-27 07:41:13 -0700678 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000679
reedf92c8662014-08-18 08:02:43 -0700680 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700681 // The root device and the canvas should always have the same pixel geometry
682 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700683 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800684 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700685 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700686 }
msarettfbfa2582016-08-12 08:29:08 -0700687
reedf92c8662014-08-18 08:02:43 -0700688 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000689}
690
reed@google.comcde92112011-07-06 20:00:52 +0000691SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000692 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700693 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800694 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000695{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000696 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000697
halcanary96fcdcc2015-08-27 07:41:13 -0700698 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000699}
700
reedd9544982014-09-09 18:46:22 -0700701static SkBitmap make_nopixels(int width, int height) {
702 SkBitmap bitmap;
703 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
704 return bitmap;
705}
706
707class SkNoPixelsBitmapDevice : public SkBitmapDevice {
708public:
robertphillipsfcf78292015-06-19 11:49:52 -0700709 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
710 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800711 {
712 this->setOrigin(bounds.x(), bounds.y());
713 }
reedd9544982014-09-09 18:46:22 -0700714
715private:
piotaixrb5fae932014-09-24 13:03:30 -0700716
reedd9544982014-09-09 18:46:22 -0700717 typedef SkBitmapDevice INHERITED;
718};
719
reed96a857e2015-01-25 10:33:58 -0800720SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000721 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800722 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800723 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000724{
725 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700726
halcanary385fe4d2015-08-26 13:07:48 -0700727 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
728 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700729}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000730
reed78e27682014-11-19 08:04:34 -0800731SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700732 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700733 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800734 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700735{
736 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700737
halcanary385fe4d2015-08-26 13:07:48 -0700738 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700739}
740
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000741SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000742 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700743 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800744 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000745{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700747
reedd9544982014-09-09 18:46:22 -0700748 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000749}
750
robertphillipsfcf78292015-06-19 11:49:52 -0700751SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
752 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700753 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800754 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700755{
756 inc_canvas();
757
758 this->init(device, flags);
759}
760
reed4a8126e2014-09-22 07:29:03 -0700761SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700762 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700763 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800764 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700765{
766 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700767
Hal Canary704cd322016-11-07 14:13:52 -0500768 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
769 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700770}
reed29c857d2014-09-21 10:25:07 -0700771
reed4a8126e2014-09-22 07:29:03 -0700772SkCanvas::SkCanvas(const SkBitmap& bitmap)
773 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
774 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800775 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700776{
777 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700778
Hal Canary704cd322016-11-07 14:13:52 -0500779 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
780 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000781}
782
783SkCanvas::~SkCanvas() {
784 // free up the contents of our deque
785 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000786
reed@android.com8a1c16f2008-12-17 15:59:43 +0000787 this->internalRestore(); // restore the last, since we're going away
788
halcanary385fe4d2015-08-26 13:07:48 -0700789 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000790
reed@android.com8a1c16f2008-12-17 15:59:43 +0000791 dec_canvas();
792}
793
fmalita53d9f1c2016-01-25 06:23:54 -0800794#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000795SkDrawFilter* SkCanvas::getDrawFilter() const {
796 return fMCRec->fFilter;
797}
798
799SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700800 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000801 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
802 return filter;
803}
fmalita77650002016-01-21 18:47:11 -0800804#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000806SkMetaData& SkCanvas::getMetaData() {
807 // metadata users are rare, so we lazily allocate it. If that changes we
808 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700809 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000810 fMetaData = new SkMetaData;
811 }
812 return *fMetaData;
813}
814
reed@android.com8a1c16f2008-12-17 15:59:43 +0000815///////////////////////////////////////////////////////////////////////////////
816
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000817void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700818 this->onFlush();
819}
820
821void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000822 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000823 if (device) {
824 device->flush();
825 }
826}
827
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000828SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000829 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000830 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
831}
832
senorblancoafc7cce2016-02-02 18:44:15 -0800833SkIRect SkCanvas::getTopLayerBounds() const {
834 SkBaseDevice* d = this->getTopDevice();
835 if (!d) {
836 return SkIRect::MakeEmpty();
837 }
838 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
839}
840
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000841SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000842 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000843 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000844 SkASSERT(rec && rec->fLayer);
845 return rec->fLayer->fDevice;
846}
847
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000848SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000849 if (updateMatrixClip) {
850 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
851 }
reed@google.com9266fed2011-03-30 00:18:03 +0000852 return fMCRec->fTopLayer->fDevice;
853}
854
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000855bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700856 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000857 return false;
858 }
859
860 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700861 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700862 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000863 return false;
864 }
865 weAllocated = true;
866 }
867
reedcf01e312015-05-23 19:14:51 -0700868 SkAutoPixmapUnlock unlocker;
869 if (bitmap->requestLock(&unlocker)) {
870 const SkPixmap& pm = unlocker.pixmap();
871 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
872 return true;
873 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000874 }
875
876 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700877 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000878 }
879 return false;
880}
reed@google.com51df9e32010-12-23 19:29:18 +0000881
bsalomon@google.comc6980972011-11-02 19:57:21 +0000882bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000883 SkIRect r = srcRect;
884 const SkISize size = this->getBaseLayerSize();
885 if (!r.intersect(0, 0, size.width(), size.height())) {
886 bitmap->reset();
887 return false;
888 }
889
reed84825042014-09-02 12:50:45 -0700890 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000891 // bitmap will already be reset.
892 return false;
893 }
894 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
895 bitmap->reset();
896 return false;
897 }
898 return true;
899}
900
reed96472de2014-12-10 09:53:42 -0800901bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000902 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000903 if (!device) {
904 return false;
905 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000906 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800907
reed96472de2014-12-10 09:53:42 -0800908 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
909 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000910 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000911 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000912
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000913 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800914 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000915}
916
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000917bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700918 SkAutoPixmapUnlock unlocker;
919 if (bitmap.requestLock(&unlocker)) {
920 const SkPixmap& pm = unlocker.pixmap();
921 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000922 }
923 return false;
924}
925
926bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
927 int x, int y) {
928 switch (origInfo.colorType()) {
929 case kUnknown_SkColorType:
930 case kIndex_8_SkColorType:
931 return false;
932 default:
933 break;
934 }
halcanary96fcdcc2015-08-27 07:41:13 -0700935 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000936 return false;
937 }
938
939 const SkISize size = this->getBaseLayerSize();
940 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
941 if (!target.intersect(0, 0, size.width(), size.height())) {
942 return false;
943 }
944
945 SkBaseDevice* device = this->getDevice();
946 if (!device) {
947 return false;
948 }
949
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000950 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700951 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000952
953 // if x or y are negative, then we have to adjust pixels
954 if (x > 0) {
955 x = 0;
956 }
957 if (y > 0) {
958 y = 0;
959 }
960 // here x,y are either 0 or negative
961 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
962
reed4af35f32014-06-27 17:47:49 -0700963 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700964 const bool completeOverwrite = info.dimensions() == size;
965 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700966
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000967 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000968 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000969}
reed@google.com51df9e32010-12-23 19:29:18 +0000970
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971//////////////////////////////////////////////////////////////////////////////
972
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973void SkCanvas::updateDeviceCMCache() {
974 if (fDeviceCMDirty) {
975 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700976 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000978
halcanary96fcdcc2015-08-27 07:41:13 -0700979 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700980 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000982 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000983 do {
reedde6c5312016-09-02 12:10:07 -0700984 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700985 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986 }
987 fDeviceCMDirty = false;
988 }
989}
990
reed@android.com8a1c16f2008-12-17 15:59:43 +0000991///////////////////////////////////////////////////////////////////////////////
992
reed2ff1fce2014-12-11 07:07:37 -0800993void SkCanvas::checkForDeferredSave() {
994 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800995 this->doSave();
996 }
997}
998
reedf0090cb2014-11-26 08:55:51 -0800999int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -08001000#ifdef SK_DEBUG
1001 int count = 0;
1002 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1003 for (;;) {
1004 const MCRec* rec = (const MCRec*)iter.next();
1005 if (!rec) {
1006 break;
1007 }
1008 count += 1 + rec->fDeferredSaveCount;
1009 }
1010 SkASSERT(count == fSaveCount);
1011#endif
1012 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001013}
1014
1015int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001016 fSaveCount += 1;
1017 fMCRec->fDeferredSaveCount += 1;
1018 return this->getSaveCount() - 1; // return our prev value
1019}
1020
1021void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001022 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001023
1024 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1025 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001026 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001027}
1028
1029void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001030 if (fMCRec->fDeferredSaveCount > 0) {
1031 SkASSERT(fSaveCount > 1);
1032 fSaveCount -= 1;
1033 fMCRec->fDeferredSaveCount -= 1;
1034 } else {
1035 // check for underflow
1036 if (fMCStack.count() > 1) {
1037 this->willRestore();
1038 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001039 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001040 this->internalRestore();
1041 this->didRestore();
1042 }
reedf0090cb2014-11-26 08:55:51 -08001043 }
1044}
1045
1046void SkCanvas::restoreToCount(int count) {
1047 // sanity check
1048 if (count < 1) {
1049 count = 1;
1050 }
mtkleinf0f14112014-12-12 08:46:25 -08001051
reedf0090cb2014-11-26 08:55:51 -08001052 int n = this->getSaveCount() - count;
1053 for (int i = 0; i < n; ++i) {
1054 this->restore();
1055 }
1056}
1057
reed2ff1fce2014-12-11 07:07:37 -08001058void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001060 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001061 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001062
reed687fa1c2015-04-07 08:00:56 -07001063 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001064}
1065
reed4960eee2015-12-18 07:09:18 -08001066bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001067 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001068}
1069
reed4960eee2015-12-18 07:09:18 -08001070bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001071 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001072 SkIRect clipBounds;
1073 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001074 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001075 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001076
reed96e657d2015-03-10 17:30:07 -07001077 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1078
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001079 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001080 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001081 if (bounds && !imageFilter->canComputeFastBounds()) {
1082 bounds = nullptr;
1083 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001084 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001085 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001086 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001088
reed96e657d2015-03-10 17:30:07 -07001089 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090 r.roundOut(&ir);
1091 // early exit if the layer's bounds are clipped out
1092 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001093 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001094 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001095 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001096 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001097 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098 }
1099 } else { // no user bounds, so just use the clip
1100 ir = clipBounds;
1101 }
reed180aec42015-03-11 10:39:04 -07001102 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001103
reed4960eee2015-12-18 07:09:18 -08001104 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001105 // Simplify the current clips since they will be applied properly during restore()
reed73603f32016-09-20 08:42:38 -07001106 fClipStack->clipDevRect(ir, kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001107 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001108 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001109 }
1110
1111 if (intersection) {
1112 *intersection = ir;
1113 }
1114 return true;
1115}
1116
reed4960eee2015-12-18 07:09:18 -08001117
reed4960eee2015-12-18 07:09:18 -08001118int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1119 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001120}
1121
reed70ee31b2015-12-10 13:44:45 -08001122int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001123 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1124}
1125
1126int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1127 SaveLayerRec rec(origRec);
1128 if (gIgnoreSaveLayerBounds) {
1129 rec.fBounds = nullptr;
1130 }
1131 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1132 fSaveCount += 1;
1133 this->internalSaveLayer(rec, strategy);
1134 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001135}
1136
reeda2217ef2016-07-20 06:04:34 -07001137void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1138 SkBaseDevice* dst, const SkMatrix& ctm,
1139 const SkClipStack* clipStack) {
1140 SkDraw draw;
1141 SkRasterClip rc;
1142 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1143 if (!dst->accessPixels(&draw.fDst)) {
1144 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001145 }
reeda2217ef2016-07-20 06:04:34 -07001146 draw.fMatrix = &SkMatrix::I();
1147 draw.fRC = &rc;
1148 draw.fClipStack = clipStack;
1149 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001150
1151 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001152 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001153
1154 int x = src->getOrigin().x() - dst->getOrigin().x();
1155 int y = src->getOrigin().y() - dst->getOrigin().y();
1156 auto special = src->snapSpecial();
1157 if (special) {
1158 dst->drawSpecial(draw, special.get(), x, y, p);
1159 }
robertphillips7354a4b2015-12-16 05:08:27 -08001160}
reed70ee31b2015-12-10 13:44:45 -08001161
reed129ed1c2016-02-22 06:42:31 -08001162static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1163 const SkPaint* paint) {
1164 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1165 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001166 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001167 const bool hasImageFilter = paint && paint->getImageFilter();
1168
1169 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1170 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1171 // force to L32
1172 return SkImageInfo::MakeN32(w, h, alphaType);
1173 } else {
1174 // keep the same characteristics as the prev
brianosman52ede1d2016-06-20 08:25:02 -07001175 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace()));
reed129ed1c2016-02-22 06:42:31 -08001176 }
1177}
1178
reed4960eee2015-12-18 07:09:18 -08001179void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1180 const SkRect* bounds = rec.fBounds;
1181 const SkPaint* paint = rec.fPaint;
1182 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1183
reed8c30a812016-04-20 16:36:51 -07001184 SkLazyPaint lazyP;
1185 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1186 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001187 SkMatrix remainder;
1188 SkSize scale;
1189 /*
1190 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1191 * but they do handle scaling. To accommodate this, we do the following:
1192 *
1193 * 1. Stash off the current CTM
1194 * 2. Decompose the CTM into SCALE and REMAINDER
1195 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1196 * contains the REMAINDER
1197 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1198 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1199 * of the original imagefilter, and draw that (via drawSprite)
1200 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1201 *
1202 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1203 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1204 */
reed96a04f32016-04-25 09:25:15 -07001205 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001206 stashedMatrix.decomposeScale(&scale, &remainder))
1207 {
1208 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1209 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1210 SkPaint* p = lazyP.set(*paint);
1211 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1212 SkFilterQuality::kLow_SkFilterQuality,
1213 sk_ref_sp(imageFilter)));
1214 imageFilter = p->getImageFilter();
1215 paint = p;
1216 }
reed8c30a812016-04-20 16:36:51 -07001217
junov@chromium.orga907ac32012-02-24 21:54:07 +00001218 // do this before we create the layer. We don't call the public save() since
1219 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001220 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001221
1222 fDeviceCMDirty = true;
1223
1224 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001225 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001226 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001227 }
1228
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001229 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1230 // the clipRectBounds() call above?
1231 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001232 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001233 }
1234
reed4960eee2015-12-18 07:09:18 -08001235 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001236 SkPixelGeometry geo = fProps.pixelGeometry();
1237 if (paint) {
reed76033be2015-03-14 10:54:31 -07001238 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001239 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001240 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001241 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001242 }
1243 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244
robertphillips5139e502016-07-19 05:10:40 -07001245 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001246 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001247 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001248 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001249 }
reedb2db8982014-11-13 12:41:02 -08001250
robertphillips5139e502016-07-19 05:10:40 -07001251 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001252 paint);
1253
Hal Canary704cd322016-11-07 14:13:52 -05001254 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001255 {
reed70ee31b2015-12-10 13:44:45 -08001256 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001257 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001258 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001259 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
reedcd4051e2016-07-15 09:41:26 -07001260 preserveLCDText);
robertphillips5139e502016-07-19 05:10:40 -07001261 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1262 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001263 return;
reed61f501f2015-04-29 08:34:00 -07001264 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001265 }
robertphillips5139e502016-07-19 05:10:40 -07001266 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001267
Hal Canary704cd322016-11-07 14:13:52 -05001268 DeviceCM* layer =
1269 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001270
1271 layer->fNext = fMCRec->fTopLayer;
1272 fMCRec->fLayer = layer;
1273 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001274
1275 if (rec.fBackdrop) {
Hal Canary704cd322016-11-07 14:13:52 -05001276 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(),
reeda2217ef2016-07-20 06:04:34 -07001277 fMCRec->fMatrix, this->getClipStack());
1278 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001279}
1280
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001281int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001282 if (0xFF == alpha) {
1283 return this->saveLayer(bounds, nullptr);
1284 } else {
1285 SkPaint tmpPaint;
1286 tmpPaint.setAlpha(alpha);
1287 return this->saveLayer(bounds, &tmpPaint);
1288 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001289}
1290
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291void SkCanvas::internalRestore() {
1292 SkASSERT(fMCStack.count() != 0);
1293
1294 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295
reed687fa1c2015-04-07 08:00:56 -07001296 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001297
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001298 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299 DeviceCM* layer = fMCRec->fLayer; // may be null
1300 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001301 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302
1303 // now do the normal restore()
1304 fMCRec->~MCRec(); // balanced in save()
1305 fMCStack.pop_back();
1306 fMCRec = (MCRec*)fMCStack.back();
1307
1308 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1309 since if we're being recorded, we don't want to record this (the
1310 recorder will have already recorded the restore).
1311 */
bsalomon49f085d2014-09-05 13:34:00 -07001312 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001314 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001315 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001316 // restore what we smashed in internalSaveLayer
1317 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001318 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001320 delete layer;
reedb679ca82015-04-07 04:40:48 -07001321 } else {
1322 // we're at the root
reeda499f902015-05-01 09:34:31 -07001323 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001324 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001325 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001326 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001327 }
msarettfbfa2582016-08-12 08:29:08 -07001328
1329 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001330 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001331 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1332 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333}
1334
reede8f30622016-03-23 18:59:25 -07001335sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001336 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001337 props = &fProps;
1338 }
1339 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001340}
1341
reede8f30622016-03-23 18:59:25 -07001342sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001343 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001344 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001345}
1346
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001347SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001348 return this->onImageInfo();
1349}
1350
1351SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001352 SkBaseDevice* dev = this->getDevice();
1353 if (dev) {
1354 return dev->imageInfo();
1355 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001356 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001357 }
1358}
1359
brianosman898235c2016-04-06 07:38:23 -07001360bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001361 return this->onGetProps(props);
1362}
1363
1364bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001365 SkBaseDevice* dev = this->getDevice();
1366 if (dev) {
1367 if (props) {
1368 *props = fProps;
1369 }
1370 return true;
1371 } else {
1372 return false;
1373 }
1374}
1375
reed6ceeebd2016-03-09 14:26:26 -08001376bool SkCanvas::peekPixels(SkPixmap* pmap) {
1377 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001378}
1379
reed884e97c2015-05-26 11:31:54 -07001380bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001381 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001382 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001383}
1384
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001385void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001386 SkPixmap pmap;
1387 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001388 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001389 }
1390 if (info) {
1391 *info = pmap.info();
1392 }
1393 if (rowBytes) {
1394 *rowBytes = pmap.rowBytes();
1395 }
1396 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001397 *origin = this->getTopDevice(false)->getOrigin();
1398 }
reed884e97c2015-05-26 11:31:54 -07001399 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001400}
1401
reed884e97c2015-05-26 11:31:54 -07001402bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001403 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001404 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001405}
1406
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001408
reed7503d602016-07-15 14:23:29 -07001409void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001410 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001411 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412 paint = &tmp;
1413 }
reed@google.com4b226022011-01-11 18:32:13 +00001414
reed@google.com8926b162012-03-23 15:36:36 +00001415 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001416
reed@android.com8a1c16f2008-12-17 15:59:43 +00001417 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001418 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001419 paint = &looper.paint();
1420 SkImageFilter* filter = paint->getImageFilter();
1421 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001422 if (filter) {
1423 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1424 if (specialImage) {
1425 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1426 }
reed@google.com76dd2772012-01-05 21:15:07 +00001427 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001428 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001429 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001430 }
reeda2217ef2016-07-20 06:04:34 -07001431
reed@google.com4e2b3d32011-04-07 14:18:59 +00001432 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433}
1434
reed32704672015-12-16 08:27:10 -08001435/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001436
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001437void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001438 if (dx || dy) {
1439 this->checkForDeferredSave();
1440 fDeviceCMDirty = true;
1441 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001442
reedfe69b502016-09-12 06:31:48 -07001443 // Translate shouldn't affect the is-scale-translateness of the matrix.
1444 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001445
reedfe69b502016-09-12 06:31:48 -07001446 this->didTranslate(dx,dy);
1447 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448}
1449
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001450void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001451 SkMatrix m;
1452 m.setScale(sx, sy);
1453 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001454}
1455
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001456void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001457 SkMatrix m;
1458 m.setRotate(degrees);
1459 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001460}
1461
bungeman7438bfc2016-07-12 15:01:19 -07001462void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1463 SkMatrix m;
1464 m.setRotate(degrees, px, py);
1465 this->concat(m);
1466}
1467
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001468void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001469 SkMatrix m;
1470 m.setSkew(sx, sy);
1471 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001472}
1473
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001474void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001475 if (matrix.isIdentity()) {
1476 return;
1477 }
1478
reed2ff1fce2014-12-11 07:07:37 -08001479 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001480 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001481 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001482 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001483 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001484}
1485
reed8c30a812016-04-20 16:36:51 -07001486void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001487 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001488 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001489 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001490}
1491
1492void SkCanvas::setMatrix(const SkMatrix& matrix) {
1493 this->checkForDeferredSave();
1494 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001495 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001496}
1497
reed@android.com8a1c16f2008-12-17 15:59:43 +00001498void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001499 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001500}
1501
vjiaoblack95302da2016-07-21 10:25:54 -07001502#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001503void SkCanvas::translateZ(SkScalar z) {
1504 this->checkForDeferredSave();
1505 this->fMCRec->fCurDrawDepth += z;
1506 this->didTranslateZ(z);
1507}
1508
1509SkScalar SkCanvas::getZ() const {
1510 return this->fMCRec->fCurDrawDepth;
1511}
1512
vjiaoblack95302da2016-07-21 10:25:54 -07001513void SkCanvas::setLights(sk_sp<SkLights> lights) {
1514 this->fLights = lights;
1515}
1516
1517sk_sp<SkLights> SkCanvas::getLights() const {
1518 return this->fLights;
1519}
1520#endif
1521
reed@android.com8a1c16f2008-12-17 15:59:43 +00001522//////////////////////////////////////////////////////////////////////////////
1523
reed73603f32016-09-20 08:42:38 -07001524void SkCanvas::clipRect(const SkRect& rect, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001525 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001526 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1527 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001528}
1529
reed73603f32016-09-20 08:42:38 -07001530void SkCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001531 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reedc64eff52015-11-21 12:39:45 -08001532 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001533 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1534 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1535 isAA);
reedc64eff52015-11-21 12:39:45 -08001536 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001537 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001538}
1539
reed73603f32016-09-20 08:42:38 -07001540void SkCanvas::clipRRect(const SkRRect& rrect, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001541 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001542 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001543 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001544 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1545 } else {
1546 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001547 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001548}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001549
reed73603f32016-09-20 08:42:38 -07001550void SkCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001551 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001552
Brian Salomona3b45d42016-10-03 11:36:16 -04001553 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001554
Brian Salomona3b45d42016-10-03 11:36:16 -04001555 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1556 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1557 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1558 isAA);
1559 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1560 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001561}
1562
reed73603f32016-09-20 08:42:38 -07001563void SkCanvas::clipPath(const SkPath& path, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001564 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001565 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001566
1567 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1568 SkRect r;
1569 if (path.isRect(&r)) {
1570 this->onClipRect(r, op, edgeStyle);
1571 return;
1572 }
1573 SkRRect rrect;
1574 if (path.isOval(&r)) {
1575 rrect.setOval(r);
1576 this->onClipRRect(rrect, op, edgeStyle);
1577 return;
1578 }
1579 if (path.isRRect(&rrect)) {
1580 this->onClipRRect(rrect, op, edgeStyle);
1581 return;
1582 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001583 }
robertphillips39f05382015-11-24 09:30:12 -08001584
1585 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001586}
1587
reed73603f32016-09-20 08:42:38 -07001588void SkCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001589 AutoValidateClip avc(this);
1590
reed@android.com8a1c16f2008-12-17 15:59:43 +00001591 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001592 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001593
Brian Salomona3b45d42016-10-03 11:36:16 -04001594 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001595
Brian Salomona3b45d42016-10-03 11:36:16 -04001596 const SkPath* rasterClipPath = &path;
1597 const SkMatrix* matrix = &fMCRec->fMatrix;
1598 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001599 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001600 isAA = getClipStack()->asPath(&tempPath);
1601 rasterClipPath = &tempPath;
1602 matrix = &SkMatrix::I();
reed73603f32016-09-20 08:42:38 -07001603 op = kReplace_Op;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001604 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001605 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1606 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001607 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001608}
1609
reed73603f32016-09-20 08:42:38 -07001610void SkCanvas::clipRegion(const SkRegion& rgn, ClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001611 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001612 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001613}
1614
reed73603f32016-09-20 08:42:38 -07001615void SkCanvas::onClipRegion(const SkRegion& rgn, ClipOp op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001616 AutoValidateClip avc(this);
1617
reed@android.com8a1c16f2008-12-17 15:59:43 +00001618 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001619
reed@google.com5c3d1472011-02-22 19:12:23 +00001620 // todo: signal fClipStack that we have a region, and therefore (I guess)
1621 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001622 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001623
reed73603f32016-09-20 08:42:38 -07001624 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001625 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001626}
1627
reed@google.com819c9212011-02-23 18:56:55 +00001628#ifdef SK_DEBUG
1629void SkCanvas::validateClip() const {
1630 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001631 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001632 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001633 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001634 return;
1635 }
1636
reed@google.com819c9212011-02-23 18:56:55 +00001637 SkIRect ir;
1638 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001639 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001640
reed687fa1c2015-04-07 08:00:56 -07001641 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001642 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001643 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001644 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001645 case SkClipStack::Element::kRect_Type:
1646 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001647 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001648 break;
1649 case SkClipStack::Element::kEmpty_Type:
1650 tmpClip.setEmpty();
1651 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001652 default: {
1653 SkPath path;
1654 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001655 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1656 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001657 break;
1658 }
reed@google.com819c9212011-02-23 18:56:55 +00001659 }
1660 }
reed@google.com819c9212011-02-23 18:56:55 +00001661}
1662#endif
1663
reed@google.com90c07ea2012-04-13 13:50:27 +00001664void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001665 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001666 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001667
halcanary96fcdcc2015-08-27 07:41:13 -07001668 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001669 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001670 }
1671}
1672
reed@google.com5c3d1472011-02-22 19:12:23 +00001673///////////////////////////////////////////////////////////////////////////////
1674
reed@google.com754de5f2014-02-24 19:38:20 +00001675bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001676 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001677}
1678
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001679bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001680 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001681}
1682
msarettfbfa2582016-08-12 08:29:08 -07001683static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1684#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1685 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1686 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1687 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1688 return 0xF != _mm_movemask_ps(mask);
1689#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1690 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1691 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1692 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1693 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1694#else
1695 SkRect devRectAsRect;
1696 SkRect devClipAsRect;
1697 devRect.store(&devRectAsRect.fLeft);
1698 devClip.store(&devClipAsRect.fLeft);
1699 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1700#endif
1701}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001702
msarettfbfa2582016-08-12 08:29:08 -07001703// It's important for this function to not be inlined. Otherwise the compiler will share code
1704// between the fast path and the slow path, resulting in two slow paths.
1705static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1706 const SkMatrix& matrix) {
1707 SkRect deviceRect;
1708 matrix.mapRect(&deviceRect, src);
1709 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1710}
1711
1712bool SkCanvas::quickReject(const SkRect& src) const {
1713#ifdef SK_DEBUG
1714 // Verify that fDeviceClipBounds are set properly.
1715 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001716 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001717 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001718 } else {
msarettfbfa2582016-08-12 08:29:08 -07001719 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001720 }
msarettfbfa2582016-08-12 08:29:08 -07001721
msarett9637ea92016-08-18 14:03:30 -07001722 // Verify that fIsScaleTranslate is set properly.
1723 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001724#endif
1725
msarett9637ea92016-08-18 14:03:30 -07001726 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001727 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1728 }
1729
1730 // We inline the implementation of mapScaleTranslate() for the fast path.
1731 float sx = fMCRec->fMatrix.getScaleX();
1732 float sy = fMCRec->fMatrix.getScaleY();
1733 float tx = fMCRec->fMatrix.getTranslateX();
1734 float ty = fMCRec->fMatrix.getTranslateY();
1735 Sk4f scale(sx, sy, sx, sy);
1736 Sk4f trans(tx, ty, tx, ty);
1737
1738 // Apply matrix.
1739 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1740
1741 // Make sure left < right, top < bottom.
1742 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1743 Sk4f min = Sk4f::Min(ltrb, rblt);
1744 Sk4f max = Sk4f::Max(ltrb, rblt);
1745 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1746 // ARM this sequence generates the fastest (a single instruction).
1747 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1748
1749 // Check if the device rect is NaN or outside the clip.
1750 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001751}
1752
reed@google.com3b3e8952012-08-16 20:53:31 +00001753bool SkCanvas::quickReject(const SkPath& path) const {
1754 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001755}
1756
reed@google.com3b3e8952012-08-16 20:53:31 +00001757bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001758 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001759 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001760 return false;
1761 }
1762
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001763 SkMatrix inverse;
1764 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001765 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001766 if (bounds) {
1767 bounds->setEmpty();
1768 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001769 return false;
1770 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001771
bsalomon49f085d2014-09-05 13:34:00 -07001772 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001773 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001774 // adjust it outwards in case we are antialiasing
1775 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001776
reed@google.com8f4d2302013-12-17 16:44:46 +00001777 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1778 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001779 inverse.mapRect(bounds, r);
1780 }
1781 return true;
1782}
1783
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001784bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001785 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001786 if (clip.isEmpty()) {
1787 if (bounds) {
1788 bounds->setEmpty();
1789 }
1790 return false;
1791 }
1792
bsalomon49f085d2014-09-05 13:34:00 -07001793 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001794 *bounds = clip.getBounds();
1795 }
1796 return true;
1797}
1798
reed@android.com8a1c16f2008-12-17 15:59:43 +00001799const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001800 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001801}
1802
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001803const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001804 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001805}
1806
Brian Osman11052242016-10-27 14:47:55 -04001807GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001808 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001809 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001810}
1811
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001812GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001813 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001814 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001815}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001816
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001817void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1818 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001819 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001820 if (outer.isEmpty()) {
1821 return;
1822 }
1823 if (inner.isEmpty()) {
1824 this->drawRRect(outer, paint);
1825 return;
1826 }
1827
1828 // We don't have this method (yet), but technically this is what we should
1829 // be able to assert...
1830 // SkASSERT(outer.contains(inner));
1831 //
1832 // For now at least check for containment of bounds
1833 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1834
1835 this->onDrawDRRect(outer, inner, paint);
1836}
1837
reed41af9662015-01-05 07:49:08 -08001838// These need to stop being virtual -- clients need to override the onDraw... versions
1839
1840void SkCanvas::drawPaint(const SkPaint& paint) {
1841 this->onDrawPaint(paint);
1842}
1843
1844void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1845 this->onDrawRect(r, paint);
1846}
1847
msarettdca352e2016-08-26 06:37:45 -07001848void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1849 if (region.isEmpty()) {
1850 return;
1851 }
1852
1853 if (region.isRect()) {
1854 return this->drawIRect(region.getBounds(), paint);
1855 }
1856
1857 this->onDrawRegion(region, paint);
1858}
1859
reed41af9662015-01-05 07:49:08 -08001860void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1861 this->onDrawOval(r, paint);
1862}
1863
1864void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1865 this->onDrawRRect(rrect, paint);
1866}
1867
1868void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1869 this->onDrawPoints(mode, count, pts, paint);
1870}
1871
1872void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001873 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001874 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Mike Reedfaba3712016-11-03 14:45:31 -04001875 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, bmode,
reed41af9662015-01-05 07:49:08 -08001876 indices, indexCount, paint);
1877}
1878
1879void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1880 this->onDrawPath(path, paint);
1881}
1882
reeda85d4d02015-05-06 12:56:48 -07001883void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001884 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001885 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001886}
1887
reede47829b2015-08-06 10:02:53 -07001888void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1889 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001890 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001891 if (dst.isEmpty() || src.isEmpty()) {
1892 return;
1893 }
1894 this->onDrawImageRect(image, &src, dst, paint, constraint);
1895}
reed41af9662015-01-05 07:49:08 -08001896
reed84984ef2015-07-17 07:09:43 -07001897void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1898 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001899 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001900 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001901}
1902
reede47829b2015-08-06 10:02:53 -07001903void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1904 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001905 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001906 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1907 constraint);
1908}
reede47829b2015-08-06 10:02:53 -07001909
reed4c21dc52015-06-25 12:32:03 -07001910void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1911 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001912 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001913 if (dst.isEmpty()) {
1914 return;
1915 }
msarett552bca92016-08-03 06:53:26 -07001916 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1917 this->onDrawImageNine(image, center, dst, paint);
1918 } else {
reede47829b2015-08-06 10:02:53 -07001919 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001920 }
reed4c21dc52015-06-25 12:32:03 -07001921}
1922
msarett16882062016-08-16 09:31:08 -07001923void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1924 const SkPaint* paint) {
1925 RETURN_ON_NULL(image);
1926 if (dst.isEmpty()) {
1927 return;
1928 }
msarett71df2d72016-09-30 12:41:42 -07001929
1930 SkIRect bounds;
1931 Lattice latticePlusBounds = lattice;
1932 if (!latticePlusBounds.fBounds) {
1933 bounds = SkIRect::MakeWH(image->width(), image->height());
1934 latticePlusBounds.fBounds = &bounds;
1935 }
1936
1937 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1938 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001939 } else {
1940 this->drawImageRect(image, dst, paint);
1941 }
1942}
1943
reed41af9662015-01-05 07:49:08 -08001944void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001945 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001946 return;
1947 }
reed41af9662015-01-05 07:49:08 -08001948 this->onDrawBitmap(bitmap, dx, dy, paint);
1949}
1950
reede47829b2015-08-06 10:02:53 -07001951void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001952 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001953 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001954 return;
1955 }
reede47829b2015-08-06 10:02:53 -07001956 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001957}
1958
reed84984ef2015-07-17 07:09:43 -07001959void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1960 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001961 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001962}
1963
reede47829b2015-08-06 10:02:53 -07001964void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1965 SrcRectConstraint constraint) {
1966 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1967 constraint);
1968}
reede47829b2015-08-06 10:02:53 -07001969
reed41af9662015-01-05 07:49:08 -08001970void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1971 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001972 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001973 return;
1974 }
msarett552bca92016-08-03 06:53:26 -07001975 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1976 this->onDrawBitmapNine(bitmap, center, dst, paint);
1977 } else {
reeda5517e22015-07-14 10:54:12 -07001978 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001979 }
reed41af9662015-01-05 07:49:08 -08001980}
1981
msarettc573a402016-08-02 08:05:56 -07001982void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1983 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001984 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001985 return;
1986 }
msarett71df2d72016-09-30 12:41:42 -07001987
1988 SkIRect bounds;
1989 Lattice latticePlusBounds = lattice;
1990 if (!latticePlusBounds.fBounds) {
1991 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1992 latticePlusBounds.fBounds = &bounds;
1993 }
1994
1995 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1996 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001997 } else {
msarett16882062016-08-16 09:31:08 -07001998 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07001999 }
msarettc573a402016-08-02 08:05:56 -07002000}
2001
reed71c3c762015-06-24 10:29:17 -07002002void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002003 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002004 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002005 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002006 if (count <= 0) {
2007 return;
2008 }
2009 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002010 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002011 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002012}
2013
reedf70b5312016-03-04 16:36:20 -08002014void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2015 if (key) {
2016 this->onDrawAnnotation(rect, key, value);
2017 }
2018}
2019
reede47829b2015-08-06 10:02:53 -07002020void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2021 const SkPaint* paint, SrcRectConstraint constraint) {
2022 if (src) {
2023 this->drawImageRect(image, *src, dst, paint, constraint);
2024 } else {
2025 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2026 dst, paint, constraint);
2027 }
2028}
2029void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2030 const SkPaint* paint, SrcRectConstraint constraint) {
2031 if (src) {
2032 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2033 } else {
2034 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2035 dst, paint, constraint);
2036 }
2037}
2038
tomhudsoncb3bd182016-05-18 07:24:16 -07002039void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2040 SkIRect layer_bounds = this->getTopLayerBounds();
2041 if (matrix) {
2042 *matrix = this->getTotalMatrix();
2043 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2044 }
2045 if (clip_bounds) {
2046 this->getClipDeviceBounds(clip_bounds);
2047 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2048 }
2049}
2050
reed@android.com8a1c16f2008-12-17 15:59:43 +00002051//////////////////////////////////////////////////////////////////////////////
2052// These are the virtual drawing methods
2053//////////////////////////////////////////////////////////////////////////////
2054
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002055void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002056 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002057 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2058 }
2059}
2060
reed41af9662015-01-05 07:49:08 -08002061void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002062 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002063 this->internalDrawPaint(paint);
2064}
2065
2066void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002067 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002068
2069 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002070 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002071 }
2072
reed@google.com4e2b3d32011-04-07 14:18:59 +00002073 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002074}
2075
reed41af9662015-01-05 07:49:08 -08002076void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2077 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002078 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002079 if ((long)count <= 0) {
2080 return;
2081 }
2082
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002083 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002084 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002085 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002086 // special-case 2 points (common for drawing a single line)
2087 if (2 == count) {
2088 r.set(pts[0], pts[1]);
2089 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002090 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002091 }
senorblanco87e066e2015-10-28 11:23:36 -07002092 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2093 return;
2094 }
2095 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002096 }
reed@google.coma584aed2012-05-16 14:06:02 +00002097
halcanary96fcdcc2015-08-27 07:41:13 -07002098 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002099
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002100 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002101
reed@android.com8a1c16f2008-12-17 15:59:43 +00002102 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002103 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002104 }
reed@google.com4b226022011-01-11 18:32:13 +00002105
reed@google.com4e2b3d32011-04-07 14:18:59 +00002106 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002107}
2108
reed4a167172016-08-18 17:15:25 -07002109static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2110 return ((intptr_t)paint.getImageFilter() |
2111#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2112 (intptr_t)canvas->getDrawFilter() |
2113#endif
2114 (intptr_t)paint.getLooper() ) != 0;
2115}
2116
reed41af9662015-01-05 07:49:08 -08002117void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002118 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002119 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002120 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002121 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002122 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2123 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2124 SkRect tmp(r);
2125 tmp.sort();
2126
senorblanco87e066e2015-10-28 11:23:36 -07002127 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2128 return;
2129 }
2130 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002131 }
reed@google.com4b226022011-01-11 18:32:13 +00002132
reed4a167172016-08-18 17:15:25 -07002133 if (needs_autodrawlooper(this, paint)) {
2134 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002135
reed4a167172016-08-18 17:15:25 -07002136 while (iter.next()) {
2137 iter.fDevice->drawRect(iter, r, looper.paint());
2138 }
2139
2140 LOOPER_END
2141 } else {
2142 this->predrawNotify(bounds, &paint, false);
2143 SkDrawIter iter(this);
2144 while (iter.next()) {
2145 iter.fDevice->drawRect(iter, r, paint);
2146 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002147 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002148}
2149
msarett44df6512016-08-25 13:54:30 -07002150void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2151 SkRect storage;
2152 SkRect regionRect = SkRect::Make(region.getBounds());
2153 const SkRect* bounds = nullptr;
2154 if (paint.canComputeFastBounds()) {
2155 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2156 return;
2157 }
2158 bounds = &regionRect;
2159 }
2160
2161 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2162
2163 while (iter.next()) {
2164 iter.fDevice->drawRegion(iter, region, looper.paint());
2165 }
2166
2167 LOOPER_END
2168}
2169
reed41af9662015-01-05 07:49:08 -08002170void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002171 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002172 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002173 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002174 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002175 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2176 return;
2177 }
2178 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002179 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002180
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002181 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002182
2183 while (iter.next()) {
2184 iter.fDevice->drawOval(iter, oval, looper.paint());
2185 }
2186
2187 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002188}
2189
bsalomonac3aa242016-08-19 11:25:19 -07002190void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2191 SkScalar sweepAngle, bool useCenter,
2192 const SkPaint& paint) {
2193 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2194 const SkRect* bounds = nullptr;
2195 if (paint.canComputeFastBounds()) {
2196 SkRect storage;
2197 // Note we're using the entire oval as the bounds.
2198 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2199 return;
2200 }
2201 bounds = &oval;
2202 }
2203
2204 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2205
2206 while (iter.next()) {
2207 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2208 }
2209
2210 LOOPER_END
2211}
2212
reed41af9662015-01-05 07:49:08 -08002213void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002214 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002215 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002216 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002217 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002218 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2219 return;
2220 }
2221 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002222 }
2223
2224 if (rrect.isRect()) {
2225 // call the non-virtual version
2226 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002227 return;
2228 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002229 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002230 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2231 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002232 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002233
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002234 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002235
2236 while (iter.next()) {
2237 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2238 }
2239
2240 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002241}
2242
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002243void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2244 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002245 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002246 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002247 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002248 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2249 return;
2250 }
2251 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002252 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002253
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002254 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002255
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002256 while (iter.next()) {
2257 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2258 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002259
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002260 LOOPER_END
2261}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002262
reed41af9662015-01-05 07:49:08 -08002263void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002264 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002265 if (!path.isFinite()) {
2266 return;
2267 }
2268
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002269 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002270 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002271 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002272 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002273 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2274 return;
2275 }
2276 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002277 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002278
2279 const SkRect& r = path.getBounds();
2280 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002281 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002282 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002283 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002284 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002285 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002286
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002287 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002288
2289 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002290 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002291 }
2292
reed@google.com4e2b3d32011-04-07 14:18:59 +00002293 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002294}
2295
reed262a71b2015-12-05 13:07:27 -08002296bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002297 if (!paint.getImageFilter()) {
2298 return false;
2299 }
2300
2301 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002302 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002303 return false;
2304 }
2305
2306 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2307 // Once we can filter and the filter will return a result larger than itself, we should be
2308 // able to remove this constraint.
2309 // skbug.com/4526
2310 //
2311 SkPoint pt;
2312 ctm.mapXY(x, y, &pt);
2313 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2314 return ir.contains(fMCRec->fRasterClip.getBounds());
2315}
2316
reeda85d4d02015-05-06 12:56:48 -07002317void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002318 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002319 SkRect bounds = SkRect::MakeXYWH(x, y,
2320 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002321 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002322 SkRect tmp = bounds;
2323 if (paint) {
2324 paint->computeFastBounds(tmp, &tmp);
2325 }
2326 if (this->quickReject(tmp)) {
2327 return;
2328 }
reeda85d4d02015-05-06 12:56:48 -07002329 }
halcanary9d524f22016-03-29 09:03:52 -07002330
reeda85d4d02015-05-06 12:56:48 -07002331 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002332 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002333 paint = lazy.init();
2334 }
reed262a71b2015-12-05 13:07:27 -08002335
reeda2217ef2016-07-20 06:04:34 -07002336 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002337 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2338 *paint);
2339 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002340 special = this->getDevice()->makeSpecial(image);
2341 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002342 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002343 }
2344 }
2345
reed262a71b2015-12-05 13:07:27 -08002346 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2347
reeda85d4d02015-05-06 12:56:48 -07002348 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002349 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002350 if (special) {
2351 SkPoint pt;
2352 iter.fMatrix->mapXY(x, y, &pt);
2353 iter.fDevice->drawSpecial(iter, special.get(),
2354 SkScalarRoundToInt(pt.fX),
2355 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002356 } else {
2357 iter.fDevice->drawImage(iter, image, x, y, pnt);
2358 }
reeda85d4d02015-05-06 12:56:48 -07002359 }
halcanary9d524f22016-03-29 09:03:52 -07002360
reeda85d4d02015-05-06 12:56:48 -07002361 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002362}
2363
reed41af9662015-01-05 07:49:08 -08002364void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002365 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002366 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002367 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002368 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002369 if (paint) {
2370 paint->computeFastBounds(dst, &storage);
2371 }
2372 if (this->quickReject(storage)) {
2373 return;
2374 }
reeda85d4d02015-05-06 12:56:48 -07002375 }
2376 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002377 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002378 paint = lazy.init();
2379 }
halcanary9d524f22016-03-29 09:03:52 -07002380
senorblancoc41e7e12015-12-07 12:51:30 -08002381 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002382 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002383
reeda85d4d02015-05-06 12:56:48 -07002384 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002385 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002386 }
halcanary9d524f22016-03-29 09:03:52 -07002387
reeda85d4d02015-05-06 12:56:48 -07002388 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002389}
2390
reed41af9662015-01-05 07:49:08 -08002391void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002392 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002393 SkDEBUGCODE(bitmap.validate();)
2394
reed33366972015-10-08 09:22:02 -07002395 if (bitmap.drawsNothing()) {
2396 return;
2397 }
2398
2399 SkLazyPaint lazy;
2400 if (nullptr == paint) {
2401 paint = lazy.init();
2402 }
2403
2404 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2405
2406 SkRect storage;
2407 const SkRect* bounds = nullptr;
2408 if (paint->canComputeFastBounds()) {
2409 bitmap.getBounds(&storage);
2410 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002411 SkRect tmp = storage;
2412 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2413 return;
2414 }
2415 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002416 }
reed@google.com4b226022011-01-11 18:32:13 +00002417
reeda2217ef2016-07-20 06:04:34 -07002418 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002419 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2420 *paint);
2421 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002422 special = this->getDevice()->makeSpecial(bitmap);
2423 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002424 drawAsSprite = false;
2425 }
2426 }
2427
reed262a71b2015-12-05 13:07:27 -08002428 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002429
2430 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002431 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002432 if (special) {
reed262a71b2015-12-05 13:07:27 -08002433 SkPoint pt;
2434 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002435 iter.fDevice->drawSpecial(iter, special.get(),
2436 SkScalarRoundToInt(pt.fX),
2437 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002438 } else {
2439 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2440 }
reed33366972015-10-08 09:22:02 -07002441 }
msarettfbfa2582016-08-12 08:29:08 -07002442
reed33366972015-10-08 09:22:02 -07002443 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002444}
2445
reed@google.com9987ec32011-09-07 11:57:52 +00002446// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002447void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002448 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002449 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002450 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002451 return;
2452 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002453
halcanary96fcdcc2015-08-27 07:41:13 -07002454 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002455 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002456 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2457 return;
2458 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002459 }
reed@google.com3d608122011-11-21 15:16:16 +00002460
reed@google.com33535f32012-09-25 15:37:50 +00002461 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002462 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002463 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002464 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002465
senorblancoc41e7e12015-12-07 12:51:30 -08002466 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002467 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002468
reed@google.com33535f32012-09-25 15:37:50 +00002469 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002470 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002471 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002472
reed@google.com33535f32012-09-25 15:37:50 +00002473 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474}
2475
reed41af9662015-01-05 07:49:08 -08002476void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002477 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002478 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002479 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002480 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002481}
2482
reed4c21dc52015-06-25 12:32:03 -07002483void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2484 const SkPaint* paint) {
2485 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002486
halcanary96fcdcc2015-08-27 07:41:13 -07002487 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002488 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002489 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2490 return;
2491 }
reed@google.com3d608122011-11-21 15:16:16 +00002492 }
halcanary9d524f22016-03-29 09:03:52 -07002493
reed4c21dc52015-06-25 12:32:03 -07002494 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002495 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002496 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002497 }
halcanary9d524f22016-03-29 09:03:52 -07002498
senorblancoc41e7e12015-12-07 12:51:30 -08002499 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002500
reed4c21dc52015-06-25 12:32:03 -07002501 while (iter.next()) {
2502 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002503 }
halcanary9d524f22016-03-29 09:03:52 -07002504
reed4c21dc52015-06-25 12:32:03 -07002505 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002506}
2507
reed41af9662015-01-05 07:49:08 -08002508void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2509 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002510 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002511 SkDEBUGCODE(bitmap.validate();)
2512
halcanary96fcdcc2015-08-27 07:41:13 -07002513 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002514 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002515 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2516 return;
2517 }
reed4c21dc52015-06-25 12:32:03 -07002518 }
halcanary9d524f22016-03-29 09:03:52 -07002519
reed4c21dc52015-06-25 12:32:03 -07002520 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002521 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002522 paint = lazy.init();
2523 }
halcanary9d524f22016-03-29 09:03:52 -07002524
senorblancoc41e7e12015-12-07 12:51:30 -08002525 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002526
reed4c21dc52015-06-25 12:32:03 -07002527 while (iter.next()) {
2528 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2529 }
halcanary9d524f22016-03-29 09:03:52 -07002530
reed4c21dc52015-06-25 12:32:03 -07002531 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002532}
2533
msarett16882062016-08-16 09:31:08 -07002534void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2535 const SkPaint* paint) {
2536 if (nullptr == paint || paint->canComputeFastBounds()) {
2537 SkRect storage;
2538 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2539 return;
2540 }
2541 }
2542
2543 SkLazyPaint lazy;
2544 if (nullptr == paint) {
2545 paint = lazy.init();
2546 }
2547
2548 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2549
2550 while (iter.next()) {
2551 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2552 }
2553
2554 LOOPER_END
2555}
2556
2557void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2558 const SkRect& dst, const SkPaint* paint) {
2559 if (nullptr == paint || paint->canComputeFastBounds()) {
2560 SkRect storage;
2561 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2562 return;
2563 }
2564 }
2565
2566 SkLazyPaint lazy;
2567 if (nullptr == paint) {
2568 paint = lazy.init();
2569 }
2570
2571 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2572
2573 while (iter.next()) {
2574 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2575 }
2576
2577 LOOPER_END
2578}
2579
reed@google.comf67e4cf2011-03-15 20:56:58 +00002580class SkDeviceFilteredPaint {
2581public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002582 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002583 uint32_t filteredFlags = device->filterTextFlags(paint);
2584 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002585 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002586 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002587 fPaint = newPaint;
2588 } else {
2589 fPaint = &paint;
2590 }
2591 }
2592
reed@google.comf67e4cf2011-03-15 20:56:58 +00002593 const SkPaint& paint() const { return *fPaint; }
2594
2595private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002596 const SkPaint* fPaint;
2597 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002598};
2599
bungeman@google.com52c748b2011-08-22 21:30:43 +00002600void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2601 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002602 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002603 draw.fDevice->drawRect(draw, r, paint);
2604 } else {
2605 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002606 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002607 draw.fDevice->drawRect(draw, r, p);
2608 }
2609}
2610
2611void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2612 const char text[], size_t byteLength,
2613 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002614 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002615
2616 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002617 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002618 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002619 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002620 return;
2621 }
2622
2623 SkScalar width = 0;
2624 SkPoint start;
2625
2626 start.set(0, 0); // to avoid warning
2627 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2628 SkPaint::kStrikeThruText_Flag)) {
2629 width = paint.measureText(text, byteLength);
2630
2631 SkScalar offsetX = 0;
2632 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2633 offsetX = SkScalarHalf(width);
2634 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2635 offsetX = width;
2636 }
2637 start.set(x - offsetX, y);
2638 }
2639
2640 if (0 == width) {
2641 return;
2642 }
2643
2644 uint32_t flags = paint.getFlags();
2645
2646 if (flags & (SkPaint::kUnderlineText_Flag |
2647 SkPaint::kStrikeThruText_Flag)) {
2648 SkScalar textSize = paint.getTextSize();
2649 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2650 SkRect r;
2651
2652 r.fLeft = start.fX;
2653 r.fRight = start.fX + width;
2654
2655 if (flags & SkPaint::kUnderlineText_Flag) {
2656 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2657 start.fY);
2658 r.fTop = offset;
2659 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002660 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002661 }
2662 if (flags & SkPaint::kStrikeThruText_Flag) {
2663 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2664 start.fY);
2665 r.fTop = offset;
2666 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002667 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002668 }
2669 }
2670}
2671
reed@google.come0d9ce82014-04-23 04:00:17 +00002672void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2673 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002674 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002675
2676 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002677 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002678 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002679 DrawTextDecorations(iter, dfp.paint(),
2680 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002681 }
2682
reed@google.com4e2b3d32011-04-07 14:18:59 +00002683 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002684}
2685
reed@google.come0d9ce82014-04-23 04:00:17 +00002686void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2687 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002688 SkPoint textOffset = SkPoint::Make(0, 0);
2689
halcanary96fcdcc2015-08-27 07:41:13 -07002690 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002691
reed@android.com8a1c16f2008-12-17 15:59:43 +00002692 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002693 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002694 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002695 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002696 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002697
reed@google.com4e2b3d32011-04-07 14:18:59 +00002698 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002699}
2700
reed@google.come0d9ce82014-04-23 04:00:17 +00002701void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2702 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002703
2704 SkPoint textOffset = SkPoint::Make(0, constY);
2705
halcanary96fcdcc2015-08-27 07:41:13 -07002706 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002707
reed@android.com8a1c16f2008-12-17 15:59:43 +00002708 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002709 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002710 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002711 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002712 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002713
reed@google.com4e2b3d32011-04-07 14:18:59 +00002714 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002715}
2716
reed@google.come0d9ce82014-04-23 04:00:17 +00002717void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2718 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002719 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002720
reed@android.com8a1c16f2008-12-17 15:59:43 +00002721 while (iter.next()) {
2722 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002723 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002724 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002725
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002726 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002727}
2728
reed45561a02016-07-07 12:47:17 -07002729void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2730 const SkRect* cullRect, const SkPaint& paint) {
2731 if (cullRect && this->quickReject(*cullRect)) {
2732 return;
2733 }
2734
2735 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2736
2737 while (iter.next()) {
2738 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2739 }
2740
2741 LOOPER_END
2742}
2743
fmalita00d5c2c2014-08-21 08:53:26 -07002744void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2745 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002746
fmalita85d5eb92015-03-04 11:20:12 -08002747 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002748 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002749 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002750 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002751 SkRect tmp;
2752 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2753 return;
2754 }
2755 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002756 }
2757
fmalita024f9962015-03-03 19:08:17 -08002758 // We cannot filter in the looper as we normally do, because the paint is
2759 // incomplete at this point (text-related attributes are embedded within blob run paints).
2760 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002761 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002762
fmalita85d5eb92015-03-04 11:20:12 -08002763 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002764
fmalitaaa1b9122014-08-28 14:32:24 -07002765 while (iter.next()) {
2766 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002767 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002768 }
2769
fmalitaaa1b9122014-08-28 14:32:24 -07002770 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002771
2772 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002773}
2774
reed@google.come0d9ce82014-04-23 04:00:17 +00002775// These will become non-virtual, so they always call the (virtual) onDraw... method
2776void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2777 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002778 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002779 if (byteLength) {
2780 this->onDrawText(text, byteLength, x, y, paint);
2781 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002782}
2783void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2784 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002785 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002786 if (byteLength) {
2787 this->onDrawPosText(text, byteLength, pos, paint);
2788 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002789}
2790void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2791 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002792 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002793 if (byteLength) {
2794 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2795 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002796}
2797void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2798 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002799 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002800 if (byteLength) {
2801 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2802 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002803}
reed45561a02016-07-07 12:47:17 -07002804void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2805 const SkRect* cullRect, const SkPaint& paint) {
2806 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2807 if (byteLength) {
2808 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2809 }
2810}
fmalita00d5c2c2014-08-21 08:53:26 -07002811void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2812 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002813 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002814 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002815 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002816}
reed@google.come0d9ce82014-04-23 04:00:17 +00002817
reed41af9662015-01-05 07:49:08 -08002818void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2819 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002820 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002821 const uint16_t indices[], int indexCount,
2822 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002823 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002824 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002825
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826 while (iter.next()) {
2827 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002828 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002829 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002830 }
reed@google.com4b226022011-01-11 18:32:13 +00002831
reed@google.com4e2b3d32011-04-07 14:18:59 +00002832 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002833}
2834
dandovb3c9d1c2014-08-12 08:34:29 -07002835void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002836 const SkPoint texCoords[4], SkBlendMode bmode,
2837 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002838 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002839 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002840 return;
2841 }
mtklein6cfa73a2014-08-13 13:33:49 -07002842
Mike Reedfaba3712016-11-03 14:45:31 -04002843 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002844}
2845
2846void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002847 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002848 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002849 // Since a patch is always within the convex hull of the control points, we discard it when its
2850 // bounding rectangle is completely outside the current clip.
2851 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002852 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002853 if (this->quickReject(bounds)) {
2854 return;
2855 }
mtklein6cfa73a2014-08-13 13:33:49 -07002856
halcanary96fcdcc2015-08-27 07:41:13 -07002857 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002858
dandovecfff212014-08-04 10:02:00 -07002859 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002860 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002861 }
mtklein6cfa73a2014-08-13 13:33:49 -07002862
dandovecfff212014-08-04 10:02:00 -07002863 LOOPER_END
2864}
2865
reeda8db7282015-07-07 10:22:31 -07002866void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002867 RETURN_ON_NULL(dr);
2868 if (x || y) {
2869 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2870 this->onDrawDrawable(dr, &matrix);
2871 } else {
2872 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002873 }
2874}
2875
reeda8db7282015-07-07 10:22:31 -07002876void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002877 RETURN_ON_NULL(dr);
2878 if (matrix && matrix->isIdentity()) {
2879 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002880 }
reede3b38ce2016-01-08 09:18:44 -08002881 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002882}
2883
2884void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002885 // drawable bounds are no longer reliable (e.g. android displaylist)
2886 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002887 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002888}
2889
reed71c3c762015-06-24 10:29:17 -07002890void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002891 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002892 const SkRect* cull, const SkPaint* paint) {
2893 if (cull && this->quickReject(*cull)) {
2894 return;
2895 }
2896
2897 SkPaint pnt;
2898 if (paint) {
2899 pnt = *paint;
2900 }
halcanary9d524f22016-03-29 09:03:52 -07002901
halcanary96fcdcc2015-08-27 07:41:13 -07002902 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002903 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002904 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002905 }
2906 LOOPER_END
2907}
2908
reedf70b5312016-03-04 16:36:20 -08002909void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2910 SkASSERT(key);
2911
2912 SkPaint paint;
2913 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2914 while (iter.next()) {
2915 iter.fDevice->drawAnnotation(iter, rect, key, value);
2916 }
2917 LOOPER_END
2918}
2919
reed@android.com8a1c16f2008-12-17 15:59:43 +00002920//////////////////////////////////////////////////////////////////////////////
2921// These methods are NOT virtual, and therefore must call back into virtual
2922// methods, rather than actually drawing themselves.
2923//////////////////////////////////////////////////////////////////////////////
2924
reed374772b2016-10-05 17:33:02 -07002925void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002926 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002927 SkPaint paint;
2928
2929 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002930 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002931 this->drawPaint(paint);
2932}
2933
reed374772b2016-10-05 17:33:02 -07002934void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002935 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002936 SkPaint paint;
2937
2938 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002939 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002940 this->drawPaint(paint);
2941}
2942
2943void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002944 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002945 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002946
reed@android.com8a1c16f2008-12-17 15:59:43 +00002947 pt.set(x, y);
2948 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2949}
2950
2951void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002952 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002953 SkPoint pt;
2954 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002955
reed@android.com8a1c16f2008-12-17 15:59:43 +00002956 pt.set(x, y);
2957 paint.setColor(color);
2958 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2959}
2960
2961void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2962 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002963 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002964 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002965
reed@android.com8a1c16f2008-12-17 15:59:43 +00002966 pts[0].set(x0, y0);
2967 pts[1].set(x1, y1);
2968 this->drawPoints(kLines_PointMode, 2, pts, paint);
2969}
2970
2971void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2972 SkScalar right, SkScalar bottom,
2973 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002974 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002975 SkRect r;
2976
2977 r.set(left, top, right, bottom);
2978 this->drawRect(r, paint);
2979}
2980
2981void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2982 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002983 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002984 if (radius < 0) {
2985 radius = 0;
2986 }
2987
2988 SkRect r;
2989 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002990 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002991}
2992
2993void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2994 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002995 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002996 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002997 SkRRect rrect;
2998 rrect.setRectXY(r, rx, ry);
2999 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003000 } else {
3001 this->drawRect(r, paint);
3002 }
3003}
3004
reed@android.com8a1c16f2008-12-17 15:59:43 +00003005void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3006 SkScalar sweepAngle, bool useCenter,
3007 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003008 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003009 if (oval.isEmpty() || !sweepAngle) {
3010 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003011 }
bsalomon21af9ca2016-08-25 12:29:23 -07003012 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003013}
3014
3015void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3016 const SkPath& path, SkScalar hOffset,
3017 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003018 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003019 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003020
reed@android.com8a1c16f2008-12-17 15:59:43 +00003021 matrix.setTranslate(hOffset, vOffset);
3022 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3023}
3024
reed@android.comf76bacf2009-05-13 14:00:33 +00003025///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003026
3027/**
3028 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3029 * against the playback cost of recursing into the subpicture to get at its actual ops.
3030 *
3031 * For now we pick a conservatively small value, though measurement (and other heuristics like
3032 * the type of ops contained) may justify changing this value.
3033 */
3034#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003035
reedd5fa1a42014-08-09 11:08:05 -07003036void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003037 RETURN_ON_NULL(picture);
3038
reed1c2c4412015-04-30 13:09:24 -07003039 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003040 if (matrix && matrix->isIdentity()) {
3041 matrix = nullptr;
3042 }
3043 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3044 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3045 picture->playback(this);
3046 } else {
3047 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003048 }
3049}
robertphillips9b14f262014-06-04 05:40:44 -07003050
reedd5fa1a42014-08-09 11:08:05 -07003051void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3052 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003053 if (!paint || paint->canComputeFastBounds()) {
3054 SkRect bounds = picture->cullRect();
3055 if (paint) {
3056 paint->computeFastBounds(bounds, &bounds);
3057 }
3058 if (matrix) {
3059 matrix->mapRect(&bounds);
3060 }
3061 if (this->quickReject(bounds)) {
3062 return;
3063 }
3064 }
3065
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003066 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003067 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003068}
3069
vjiaoblack95302da2016-07-21 10:25:54 -07003070#ifdef SK_EXPERIMENTAL_SHADOWING
3071void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3072 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003073 const SkPaint* paint,
3074 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003075 RETURN_ON_NULL(picture);
3076
3077 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3078
vjiaoblacke6f5d562016-08-25 06:30:23 -07003079 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003080}
3081
3082void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3083 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003084 const SkPaint* paint,
3085 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003086 if (!paint || paint->canComputeFastBounds()) {
3087 SkRect bounds = picture->cullRect();
3088 if (paint) {
3089 paint->computeFastBounds(bounds, &bounds);
3090 }
3091 if (matrix) {
3092 matrix->mapRect(&bounds);
3093 }
3094 if (this->quickReject(bounds)) {
3095 return;
3096 }
3097 }
3098
3099 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3100
vjiaoblacke6f5d562016-08-25 06:30:23 -07003101 sk_sp<SkImage> povDepthMap;
3102 sk_sp<SkImage> diffuseMap;
3103
vjiaoblack904527d2016-08-09 09:32:09 -07003104 // povDepthMap
3105 {
3106 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003107 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3108 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003109 sk_sp<SkLights> povLight = builder.finish();
3110
3111 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3112 picture->cullRect().height(),
3113 kBGRA_8888_SkColorType,
3114 kOpaque_SkAlphaType);
3115
3116 // Create a new surface (that matches the backend of canvas)
3117 // to create the povDepthMap
3118 sk_sp<SkSurface> surf(this->makeSurface(info));
3119
3120 // Wrap another SPFCanvas around the surface
3121 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3122 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3123
3124 // set the depth map canvas to have the light as the user's POV
3125 depthMapCanvas->setLights(std::move(povLight));
3126
3127 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003128 povDepthMap = surf->makeImageSnapshot();
3129 }
3130
3131 // diffuseMap
3132 {
3133 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3134 picture->cullRect().height(),
3135 kBGRA_8888_SkColorType,
3136 kOpaque_SkAlphaType);
3137
3138 sk_sp<SkSurface> surf(this->makeSurface(info));
3139 surf->getCanvas()->drawPicture(picture);
3140
3141 diffuseMap = surf->makeImageSnapshot();
3142 }
vjiaoblack904527d2016-08-09 09:32:09 -07003143
3144 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3145 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003146 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3147 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003148
3149 // TODO: pass the depth to the shader in vertices, or uniforms
3150 // so we don't have to render depth and color separately
3151 for (int i = 0; i < fLights->numLights(); ++i) {
3152 // skip over ambient lights; they don't cast shadows
3153 // lights that have shadow maps do not need updating (because lights are immutable)
3154 sk_sp<SkImage> depthMap;
3155 SkISize shMapSize;
3156
3157 if (fLights->light(i).getShadowMap() != nullptr) {
3158 continue;
3159 }
3160
3161 if (fLights->light(i).isRadial()) {
3162 shMapSize.fHeight = 1;
3163 shMapSize.fWidth = (int) picture->cullRect().width();
3164
3165 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3166 kBGRA_8888_SkColorType,
3167 kOpaque_SkAlphaType);
3168
3169 // Create new surface (that matches the backend of canvas)
3170 // for each shadow map
3171 sk_sp<SkSurface> surf(this->makeSurface(info));
3172
3173 // Wrap another SPFCanvas around the surface
3174 SkCanvas* depthMapCanvas = surf->getCanvas();
3175
3176 SkLights::Builder builder;
3177 builder.add(fLights->light(i));
3178 sk_sp<SkLights> curLight = builder.finish();
3179
3180 sk_sp<SkShader> shadowMapShader;
3181 shadowMapShader = SkRadialShadowMapShader::Make(
3182 povDepthShader, curLight,
3183 (int) picture->cullRect().width(),
3184 (int) picture->cullRect().height());
3185
3186 SkPaint shadowMapPaint;
3187 shadowMapPaint.setShader(std::move(shadowMapShader));
3188
3189 depthMapCanvas->setLights(curLight);
3190
3191 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3192 diffuseMap->height()),
3193 shadowMapPaint);
3194
3195 depthMap = surf->makeImageSnapshot();
3196
3197 } else {
3198 // TODO: compute the correct size of the depth map from the light properties
3199 // TODO: maybe add a kDepth_8_SkColorType
3200 // TODO: find actual max depth of picture
3201 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3202 fLights->light(i), 255,
3203 (int) picture->cullRect().width(),
3204 (int) picture->cullRect().height());
3205
3206 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3207 kBGRA_8888_SkColorType,
3208 kOpaque_SkAlphaType);
3209
3210 // Create a new surface (that matches the backend of canvas)
3211 // for each shadow map
3212 sk_sp<SkSurface> surf(this->makeSurface(info));
3213
3214 // Wrap another SPFCanvas around the surface
3215 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3216 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3217 depthMapCanvas->setShadowParams(params);
3218
3219 // set the depth map canvas to have the light we're drawing.
3220 SkLights::Builder builder;
3221 builder.add(fLights->light(i));
3222 sk_sp<SkLights> curLight = builder.finish();
3223 depthMapCanvas->setLights(std::move(curLight));
3224
3225 depthMapCanvas->drawPicture(picture);
3226 depthMap = surf->makeImageSnapshot();
3227 }
3228
3229 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3230 fLights->light(i).setShadowMap(std::move(depthMap));
3231 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3232 // we blur the variance map
3233 SkPaint blurPaint;
3234 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3235 params.fShadowRadius, nullptr));
3236
3237 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3238 kBGRA_8888_SkColorType,
3239 kOpaque_SkAlphaType);
3240
3241 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3242
3243 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3244
3245 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3246 }
3247 }
3248
3249 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003250 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3251 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003252 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003253 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003254 diffuseMap->height(),
3255 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003256
3257 shadowPaint.setShader(shadowShader);
3258
3259 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003260}
3261#endif
3262
reed@android.com8a1c16f2008-12-17 15:59:43 +00003263///////////////////////////////////////////////////////////////////////////////
3264///////////////////////////////////////////////////////////////////////////////
3265
reed3aafe112016-08-18 12:45:34 -07003266SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003267 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003268
3269 SkASSERT(canvas);
3270
reed3aafe112016-08-18 12:45:34 -07003271 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003272 fDone = !fImpl->next();
3273}
3274
3275SkCanvas::LayerIter::~LayerIter() {
3276 fImpl->~SkDrawIter();
3277}
3278
3279void SkCanvas::LayerIter::next() {
3280 fDone = !fImpl->next();
3281}
3282
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003283SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003284 return fImpl->getDevice();
3285}
3286
3287const SkMatrix& SkCanvas::LayerIter::matrix() const {
3288 return fImpl->getMatrix();
3289}
3290
3291const SkPaint& SkCanvas::LayerIter::paint() const {
3292 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003293 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003294 paint = &fDefaultPaint;
3295 }
3296 return *paint;
3297}
3298
reed1e7f5e72016-04-27 07:49:17 -07003299const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003300int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3301int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003302
3303///////////////////////////////////////////////////////////////////////////////
3304
fmalitac3b589a2014-06-05 12:40:07 -07003305SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003306
3307///////////////////////////////////////////////////////////////////////////////
3308
3309static bool supported_for_raster_canvas(const SkImageInfo& info) {
3310 switch (info.alphaType()) {
3311 case kPremul_SkAlphaType:
3312 case kOpaque_SkAlphaType:
3313 break;
3314 default:
3315 return false;
3316 }
3317
3318 switch (info.colorType()) {
3319 case kAlpha_8_SkColorType:
3320 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003321 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003322 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003323 break;
3324 default:
3325 return false;
3326 }
3327
3328 return true;
3329}
3330
Mike Reed5df49342016-11-12 08:06:55 -06003331std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3332 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003333 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003334 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003335 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003336
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003337 SkBitmap bitmap;
3338 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003339 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003340 }
Mike Reed5df49342016-11-12 08:06:55 -06003341 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003342}
reedd5fa1a42014-08-09 11:08:05 -07003343
3344///////////////////////////////////////////////////////////////////////////////
3345
3346SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003347 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003348 : fCanvas(canvas)
3349 , fSaveCount(canvas->getSaveCount())
3350{
bsalomon49f085d2014-09-05 13:34:00 -07003351 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003352 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003353 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003354 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003355 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003356 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003357 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003358 canvas->save();
3359 }
mtklein6cfa73a2014-08-13 13:33:49 -07003360
bsalomon49f085d2014-09-05 13:34:00 -07003361 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003362 canvas->concat(*matrix);
3363 }
3364}
3365
3366SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3367 fCanvas->restoreToCount(fSaveCount);
3368}
reede8f30622016-03-23 18:59:25 -07003369
reed73603f32016-09-20 08:42:38 -07003370/////////////////////////////////
3371
3372const SkCanvas::ClipOp SkCanvas::kDifference_Op;
3373const SkCanvas::ClipOp SkCanvas::kIntersect_Op;
3374const SkCanvas::ClipOp SkCanvas::kUnion_Op;
3375const SkCanvas::ClipOp SkCanvas::kXOR_Op;
3376const SkCanvas::ClipOp SkCanvas::kReverseDifference_Op;
3377const SkCanvas::ClipOp SkCanvas::kReplace_Op;
3378
3379static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3380static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3381static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3382static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3383static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3384static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");