blob: 2dff8e9f89a5274c1a86be1a9c2322867364ea58 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
bungemand3ebb482015-08-05 13:57:49 -07008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
piotaixrb5fae932014-09-24 13:03:30 -070017#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080018#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070019#include "SkImageFilter.h"
20#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070021#include "SkLatticeIter.h"
Mike Reed5df49342016-11-12 08:06:55 -060022#include "SkMakeUnique.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
Florin Malitaee424ac2016-12-01 12:47:59 -050025#include "SkNoDrawCanvas.h"
msarettfbfa2582016-08-12 08:29:08 -070026#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070027#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070028#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000029#include "SkPicture.h"
vjiaoblackb2796fd2016-09-09 09:22:39 -070030#include "SkRadialShadowMapShader.h"
reed@google.com00177082011-10-12 14:34:30 +000031#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080032#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000033#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070034#include "SkShadowPaintFilterCanvas.h"
35#include "SkShadowShader.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000036#include "SkSmallAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080037#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000038#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070039#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000040#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000041#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080042#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070043#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080046#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000047#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070048#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070049
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000050#endif
51
reede3b38ce2016-01-08 09:18:44 -080052#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
53
reedc83a2972015-07-16 07:40:45 -070054/*
55 * Return true if the drawing this rect would hit every pixels in the canvas.
56 *
57 * Returns false if
58 * - rect does not contain the canvas' bounds
59 * - paint is not fill
60 * - paint would blur or otherwise change the coverage of the rect
61 */
62bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
63 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070064 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
65 (int)kNone_ShaderOverrideOpacity,
66 "need_matching_enums0");
67 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
68 (int)kOpaque_ShaderOverrideOpacity,
69 "need_matching_enums1");
70 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
71 (int)kNotOpaque_ShaderOverrideOpacity,
72 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070073
74 const SkISize size = this->getBaseLayerSize();
75 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
76 if (!this->getClipStack()->quickContains(bounds)) {
77 return false;
78 }
79
80 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070081 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070082 return false; // conservative
83 }
halcanaryc5769b22016-08-10 07:13:21 -070084
85 SkRect devRect;
86 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
87 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070088 return false;
89 }
90 }
91
92 if (paint) {
93 SkPaint::Style paintStyle = paint->getStyle();
94 if (!(paintStyle == SkPaint::kFill_Style ||
95 paintStyle == SkPaint::kStrokeAndFill_Style)) {
96 return false;
97 }
98 if (paint->getMaskFilter() || paint->getLooper()
99 || paint->getPathEffect() || paint->getImageFilter()) {
100 return false; // conservative
101 }
102 }
103 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
104}
105
106///////////////////////////////////////////////////////////////////////////////////////////////////
107
reedd990e2f2014-12-22 11:58:30 -0800108static bool gIgnoreSaveLayerBounds;
109void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
110 gIgnoreSaveLayerBounds = ignore;
111}
112bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
113 return gIgnoreSaveLayerBounds;
114}
115
reed0acf1b42014-12-22 16:12:38 -0800116static bool gTreatSpriteAsBitmap;
117void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
118 gTreatSpriteAsBitmap = spriteAsBitmap;
119}
120bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
121 return gTreatSpriteAsBitmap;
122}
123
reed@google.comda17f752012-08-16 18:27:05 +0000124// experimental for faster tiled drawing...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125//#define SK_TRACE_SAVERESTORE
126
127#ifdef SK_TRACE_SAVERESTORE
128 static int gLayerCounter;
129 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
130 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
131
132 static int gRecCounter;
133 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
134 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
135
136 static int gCanvasCounter;
137 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
138 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
139#else
140 #define inc_layer()
141 #define dec_layer()
142 #define inc_rec()
143 #define dec_rec()
144 #define inc_canvas()
145 #define dec_canvas()
146#endif
147
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000148typedef SkTLazy<SkPaint> SkLazyPaint;
149
reedc83a2972015-07-16 07:40:45 -0700150void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000151 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700152 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
153 ? SkSurface::kDiscard_ContentChangeMode
154 : SkSurface::kRetain_ContentChangeMode);
155 }
156}
157
158void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
159 ShaderOverrideOpacity overrideOpacity) {
160 if (fSurfaceBase) {
161 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
162 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
163 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
164 // and therefore we don't care which mode we're in.
165 //
166 if (fSurfaceBase->outstandingImageSnapshot()) {
167 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
168 mode = SkSurface::kDiscard_ContentChangeMode;
169 }
170 }
171 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000172 }
173}
174
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000177/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 The clip/matrix/proc are fields that reflect the top of the save/restore
179 stack. Whenever the canvas changes, it marks a dirty flag, and then before
180 these are used (assuming we're not on a layer) we rebuild these cache
181 values: they reflect the top of the save stack, but translated and clipped
182 by the device's XY offset and bitmap-bounds.
183*/
184struct DeviceCM {
185 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000186 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000187 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000188 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700189 const SkMatrix* fMatrix;
190 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700191 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192
reed96e657d2015-03-10 17:30:07 -0700193 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700194 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700195 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700196 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700197 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700198 {
reed2c9e2002016-07-25 08:05:22 -0700199 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000200 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700201 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000202 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000204 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700205 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700206 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000207 }
reed@google.com4b226022011-01-11 18:32:13 +0000208
mtkleinfeaadee2015-04-08 11:25:48 -0700209 void reset(const SkIRect& bounds) {
210 SkASSERT(!fPaint);
211 SkASSERT(!fNext);
212 SkASSERT(fDevice);
213 fClip.setRect(bounds);
214 }
215
reed@google.com045e62d2011-10-24 12:19:46 +0000216 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
reedde6c5312016-09-02 12:10:07 -0700217 SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000218 int x = fDevice->getOrigin().x();
219 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 int width = fDevice->width();
221 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000222
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 if ((x | y) == 0) {
224 fMatrix = &totalMatrix;
225 fClip = totalClip;
226 } else {
227 fMatrixStorage = totalMatrix;
228 fMatrixStorage.postTranslate(SkIntToScalar(-x),
229 SkIntToScalar(-y));
230 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000231
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 totalClip.translate(-x, -y, &fClip);
233 }
234
reed@google.com045e62d2011-10-24 12:19:46 +0000235 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236
237 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000238
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000240 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 SkRegion::kDifference_Op);
242 }
reed@google.com4b226022011-01-11 18:32:13 +0000243
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244#ifdef SK_DEBUG
245 if (!fClip.isEmpty()) {
246 SkIRect deviceR;
247 deviceR.set(0, 0, width, height);
248 SkASSERT(deviceR.contains(fClip.getBounds()));
249 }
250#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000251 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252};
253
254/* This is the record we keep for each save/restore level in the stack.
255 Since a level optionally copies the matrix and/or stack, we have pointers
256 for these fields. If the value is copied for this level, the copy is
257 stored in the ...Storage field, and the pointer points to that. If the
258 value is not copied for this level, we ignore ...Storage, and just point
259 at the corresponding value in the previous level in the stack.
260*/
261class SkCanvas::MCRec {
262public:
reed1f836ee2014-07-07 07:49:34 -0700263 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700264 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265 /* If there are any layers in the stack, this points to the top-most
266 one that is at or below this level in the stack (so we know what
267 bitmap/device to draw into from this level. This value is NOT
268 reference counted, since the real owner is either our fLayer field,
269 or a previous one in a lower level.)
270 */
reed2ff1fce2014-12-11 07:07:37 -0800271 DeviceCM* fTopLayer;
272 SkRasterClip fRasterClip;
273 SkMatrix fMatrix;
274 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275
vjiaoblacke5de1302016-07-13 14:05:28 -0700276 // This is the current cumulative depth (aggregate of all done translateZ calls)
277 SkScalar fCurDrawDepth;
278
reedd9544982014-09-09 18:46:22 -0700279 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700280 fFilter = nullptr;
281 fLayer = nullptr;
282 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800283 fMatrix.reset();
284 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700285 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700286
reedd9544982014-09-09 18:46:22 -0700287 // don't bother initializing fNext
288 inc_rec();
289 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700290 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
291 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700292 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700293 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700294 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800295 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700296
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 // don't bother initializing fNext
298 inc_rec();
299 }
300 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000301 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700302 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303 dec_rec();
304 }
mtkleinfeaadee2015-04-08 11:25:48 -0700305
306 void reset(const SkIRect& bounds) {
307 SkASSERT(fLayer);
308 SkASSERT(fDeferredSaveCount == 0);
309
310 fMatrix.reset();
311 fRasterClip.setRect(bounds);
312 fLayer->reset(bounds);
313 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314};
315
reed02f9ed72016-09-06 09:06:18 -0700316static SkIRect compute_device_bounds(SkBaseDevice* device) {
317 return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(),
318 device->width(), device->height());
319}
320
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321class SkDrawIter : public SkDraw {
322public:
reed3aafe112016-08-18 12:45:34 -0700323 SkDrawIter(SkCanvas* canvas) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324 canvas->updateDeviceCMCache();
325
bungeman6bd52842016-10-27 09:30:08 -0700326 fClipStack = canvas->getClipStack();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 fCurrLayer = canvas->fMCRec->fTopLayer;
reed02f9ed72016-09-06 09:06:18 -0700328
329 fMultiDeviceCS = nullptr;
330 if (fCurrLayer->fNext) {
bungeman6bd52842016-10-27 09:30:08 -0700331 fMultiDeviceCS = canvas->fClipStack.get();
reed02f9ed72016-09-06 09:06:18 -0700332 fMultiDeviceCS->save();
333 }
334 }
335
336 ~SkDrawIter() {
337 if (fMultiDeviceCS) {
338 fMultiDeviceCS->restore();
339 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 }
reed@google.com4b226022011-01-11 18:32:13 +0000341
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 bool next() {
reed02f9ed72016-09-06 09:06:18 -0700343 if (fMultiDeviceCS && fDevice) {
344 // remove the previous device's bounds
reed73603f32016-09-20 08:42:38 -0700345 fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), SkCanvas::kDifference_Op);
reed02f9ed72016-09-06 09:06:18 -0700346 }
347
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700349 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
350 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 }
352
reed@google.comf68c5e22012-02-24 16:38:58 +0000353 const DeviceCM* rec = fCurrLayer;
354 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355
356 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000357 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700359 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700360 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700361 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000363 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364
365 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700366 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000367
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368 return true;
369 }
370 return false;
371 }
reed@google.com4b226022011-01-11 18:32:13 +0000372
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000373 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700374 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000375 int getX() const { return fDevice->getOrigin().x(); }
376 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000379
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381 const DeviceCM* fCurrLayer;
382 const SkPaint* fPaint; // May be null.
reed02f9ed72016-09-06 09:06:18 -0700383 SkClipStack* fMultiDeviceCS;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384
385 typedef SkDraw INHERITED;
386};
387
388/////////////////////////////////////////////////////////////////////////////
389
reeddbc3cef2015-04-29 12:18:57 -0700390static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
391 return lazy->isValid() ? lazy->get() : lazy->set(orig);
392}
393
394/**
395 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700396 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700397 */
reedd053ce92016-03-22 10:17:23 -0700398static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700399 SkImageFilter* imgf = paint.getImageFilter();
400 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700401 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700402 }
403
reedd053ce92016-03-22 10:17:23 -0700404 SkColorFilter* imgCFPtr;
405 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700406 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700407 }
reedd053ce92016-03-22 10:17:23 -0700408 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700409
410 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700411 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700412 // there is no existing paint colorfilter, so we can just return the imagefilter's
413 return imgCF;
414 }
415
416 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
417 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700418 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700419}
420
senorblanco87e066e2015-10-28 11:23:36 -0700421/**
422 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
423 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
424 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
425 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
426 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
427 * conservative "effective" bounds based on the settings in the paint... with one exception. This
428 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
429 * deliberately ignored.
430 */
431static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
432 const SkRect& rawBounds,
433 SkRect* storage) {
434 SkPaint tmpUnfiltered(paint);
435 tmpUnfiltered.setImageFilter(nullptr);
436 if (tmpUnfiltered.canComputeFastBounds()) {
437 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
438 } else {
439 return rawBounds;
440 }
441}
442
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443class AutoDrawLooper {
444public:
senorblanco87e066e2015-10-28 11:23:36 -0700445 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
446 // paint. It's used to determine the size of the offscreen layer for filters.
447 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700448 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700449 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000450 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800451#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800453#else
454 fFilter = nullptr;
455#endif
reed4a8126e2014-09-22 07:29:03 -0700456 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000457 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700458 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000459 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460
reedd053ce92016-03-22 10:17:23 -0700461 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700462 if (simplifiedCF) {
463 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700464 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700465 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700466 fPaint = paint;
467 }
468
469 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700470 /**
471 * We implement ImageFilters for a given draw by creating a layer, then applying the
472 * imagefilter to the pixels of that layer (its backing surface/image), and then
473 * we call restore() to xfer that layer to the main canvas.
474 *
475 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
476 * 2. Generate the src pixels:
477 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
478 * return (fPaint). We then draw the primitive (using srcover) into a cleared
479 * buffer/surface.
480 * 3. Restore the layer created in #1
481 * The imagefilter is passed the buffer/surface from the layer (now filled with the
482 * src pixels of the primitive). It returns a new "filtered" buffer, which we
483 * draw onto the previous layer using the xfermode from the original paint.
484 */
reed@google.com8926b162012-03-23 15:36:36 +0000485 SkPaint tmp;
Mike Reed5e257172016-11-01 11:22:05 -0400486 tmp.setImageFilter(sk_ref_sp(fPaint->getImageFilter()));
reed374772b2016-10-05 17:33:02 -0700487 tmp.setBlendMode(fPaint->getBlendMode());
senorblanco87e066e2015-10-28 11:23:36 -0700488 SkRect storage;
489 if (rawBounds) {
490 // Make rawBounds include all paint outsets except for those due to image filters.
491 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
492 }
reedbfd5f172016-01-07 11:28:08 -0800493 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700494 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700495 fTempLayerForImageFilter = true;
496 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000497 }
498
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000499 if (SkDrawLooper* looper = paint.getLooper()) {
herbbf6d80a2016-11-15 06:26:56 -0800500 fLooperContext = fLooperContextAllocator.createWithIniter(
501 looper->contextSize(),
502 [&](void* buffer) {
503 return looper->createContext(canvas, buffer);
504 });
reed@google.com129ec222012-05-15 13:24:09 +0000505 fIsSimple = false;
506 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700507 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000508 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700509 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000510 }
511 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000512
reed@android.com8a1c16f2008-12-17 15:59:43 +0000513 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700514 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000515 fCanvas->internalRestore();
516 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000517 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000518 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000519
reed@google.com4e2b3d32011-04-07 14:18:59 +0000520 const SkPaint& paint() const {
521 SkASSERT(fPaint);
522 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000524
reed@google.com129ec222012-05-15 13:24:09 +0000525 bool next(SkDrawFilter::Type drawType) {
526 if (fDone) {
527 return false;
528 } else if (fIsSimple) {
529 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000530 return !fPaint->nothingToDraw();
531 } else {
532 return this->doNext(drawType);
533 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000534 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000535
reed@android.com8a1c16f2008-12-17 15:59:43 +0000536private:
reeddbc3cef2015-04-29 12:18:57 -0700537 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
538 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000539 SkCanvas* fCanvas;
540 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000541 SkDrawFilter* fFilter;
542 const SkPaint* fPaint;
543 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700544 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000545 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000546 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000547 SkDrawLooper::Context* fLooperContext;
548 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000549
550 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000551};
552
reed@google.com129ec222012-05-15 13:24:09 +0000553bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700554 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000555 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700556 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000557
reeddbc3cef2015-04-29 12:18:57 -0700558 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
559 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000560
reed5c476fb2015-04-20 08:04:21 -0700561 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700562 paint->setImageFilter(nullptr);
reed374772b2016-10-05 17:33:02 -0700563 paint->setBlendMode(SkBlendMode::kSrcOver);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000564 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000565
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000566 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000567 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000568 return false;
569 }
570 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000571 if (!fFilter->filter(paint, drawType)) {
572 fDone = true;
573 return false;
574 }
halcanary96fcdcc2015-08-27 07:41:13 -0700575 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000576 // no looper means we only draw once
577 fDone = true;
578 }
579 }
580 fPaint = paint;
581
582 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000583 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000584 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000585 }
586
587 // call this after any possible paint modifiers
588 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700589 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000590 return false;
591 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000592 return true;
593}
594
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595////////// macros to place around the internal draw calls //////////////////
596
reed3aafe112016-08-18 12:45:34 -0700597#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
598 this->predrawNotify(); \
599 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
600 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800601 SkDrawIter iter(this);
602
603
reed@google.com8926b162012-03-23 15:36:36 +0000604#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000605 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700606 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000607 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000608 SkDrawIter iter(this);
609
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000610#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000611 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700612 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000613 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000615
reedc83a2972015-07-16 07:40:45 -0700616#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
617 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700618 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700619 while (looper.next(type)) { \
620 SkDrawIter iter(this);
621
reed@google.com4e2b3d32011-04-07 14:18:59 +0000622#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000623
624////////////////////////////////////////////////////////////////////////////
625
msarettfbfa2582016-08-12 08:29:08 -0700626static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
627 if (bounds.isEmpty()) {
628 return SkRect::MakeEmpty();
629 }
630
631 // Expand bounds out by 1 in case we are anti-aliasing. We store the
632 // bounds as floats to enable a faster quick reject implementation.
633 SkRect dst;
634 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
635 return dst;
636}
637
mtkleinfeaadee2015-04-08 11:25:48 -0700638void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
639 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700640 fClipStack->reset();
641 fMCRec->reset(bounds);
642
643 // We're peering through a lot of structs here. Only at this scope do we
644 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
645 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700646 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700647 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700648}
649
reedd9544982014-09-09 18:46:22 -0700650SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800651 if (device && device->forceConservativeRasterClip()) {
652 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
653 }
654 // Since init() is only called once by our constructors, it is safe to perform this
655 // const-cast.
656 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
657
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000658 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700659 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800660 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700661 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700662#ifdef SK_EXPERIMENTAL_SHADOWING
663 fLights = nullptr;
664#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665
halcanary385fe4d2015-08-26 13:07:48 -0700666 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700667
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700669 new (fMCRec) MCRec(fConservativeRasterClip);
msarett9637ea92016-08-18 14:03:30 -0700670 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000671
reeda499f902015-05-01 09:34:31 -0700672 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
673 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700674 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700675 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700676
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000678
halcanary96fcdcc2015-08-27 07:41:13 -0700679 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000680
reedf92c8662014-08-18 08:02:43 -0700681 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700682 // The root device and the canvas should always have the same pixel geometry
683 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700684 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800685 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700686 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700687 }
msarettfbfa2582016-08-12 08:29:08 -0700688
reedf92c8662014-08-18 08:02:43 -0700689 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000690}
691
reed@google.comcde92112011-07-06 20:00:52 +0000692SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000693 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700694 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800695 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000696{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000697 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000698
halcanary96fcdcc2015-08-27 07:41:13 -0700699 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000700}
701
reedd9544982014-09-09 18:46:22 -0700702static SkBitmap make_nopixels(int width, int height) {
703 SkBitmap bitmap;
704 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
705 return bitmap;
706}
707
708class SkNoPixelsBitmapDevice : public SkBitmapDevice {
709public:
robertphillipsfcf78292015-06-19 11:49:52 -0700710 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
711 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800712 {
713 this->setOrigin(bounds.x(), bounds.y());
714 }
reedd9544982014-09-09 18:46:22 -0700715
716private:
piotaixrb5fae932014-09-24 13:03:30 -0700717
reedd9544982014-09-09 18:46:22 -0700718 typedef SkBitmapDevice INHERITED;
719};
720
reed96a857e2015-01-25 10:33:58 -0800721SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000722 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800723 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800724 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000725{
726 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700727
halcanary385fe4d2015-08-26 13:07:48 -0700728 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
729 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700730}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000731
reed78e27682014-11-19 08:04:34 -0800732SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700733 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700734 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800735 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700736{
737 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700738
halcanary385fe4d2015-08-26 13:07:48 -0700739 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700740}
741
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000742SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000743 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700744 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800745 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000746{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000747 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700748
reedd9544982014-09-09 18:46:22 -0700749 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750}
751
robertphillipsfcf78292015-06-19 11:49:52 -0700752SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
753 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700754 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800755 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700756{
757 inc_canvas();
758
759 this->init(device, flags);
760}
761
reed4a8126e2014-09-22 07:29:03 -0700762SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700763 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700764 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800765 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700766{
767 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700768
Hal Canary704cd322016-11-07 14:13:52 -0500769 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
770 this->init(device.get(), kDefault_InitFlags);
reed4a8126e2014-09-22 07:29:03 -0700771}
reed29c857d2014-09-21 10:25:07 -0700772
reed4a8126e2014-09-22 07:29:03 -0700773SkCanvas::SkCanvas(const SkBitmap& bitmap)
774 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
775 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800776 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700777{
778 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700779
Hal Canary704cd322016-11-07 14:13:52 -0500780 sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
781 this->init(device.get(), kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782}
783
784SkCanvas::~SkCanvas() {
785 // free up the contents of our deque
786 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000787
reed@android.com8a1c16f2008-12-17 15:59:43 +0000788 this->internalRestore(); // restore the last, since we're going away
789
halcanary385fe4d2015-08-26 13:07:48 -0700790 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000791
reed@android.com8a1c16f2008-12-17 15:59:43 +0000792 dec_canvas();
793}
794
fmalita53d9f1c2016-01-25 06:23:54 -0800795#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000796SkDrawFilter* SkCanvas::getDrawFilter() const {
797 return fMCRec->fFilter;
798}
799
800SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700801 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000802 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
803 return filter;
804}
fmalita77650002016-01-21 18:47:11 -0800805#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000807SkMetaData& SkCanvas::getMetaData() {
808 // metadata users are rare, so we lazily allocate it. If that changes we
809 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700810 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000811 fMetaData = new SkMetaData;
812 }
813 return *fMetaData;
814}
815
reed@android.com8a1c16f2008-12-17 15:59:43 +0000816///////////////////////////////////////////////////////////////////////////////
817
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000818void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700819 this->onFlush();
820}
821
822void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000823 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000824 if (device) {
825 device->flush();
826 }
827}
828
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000829SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000830 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000831 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
832}
833
senorblancoafc7cce2016-02-02 18:44:15 -0800834SkIRect SkCanvas::getTopLayerBounds() const {
835 SkBaseDevice* d = this->getTopDevice();
836 if (!d) {
837 return SkIRect::MakeEmpty();
838 }
839 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
840}
841
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000842SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000843 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000844 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845 SkASSERT(rec && rec->fLayer);
846 return rec->fLayer->fDevice;
847}
848
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000849SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000850 if (updateMatrixClip) {
851 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
852 }
reed@google.com9266fed2011-03-30 00:18:03 +0000853 return fMCRec->fTopLayer->fDevice;
854}
855
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000856bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700857 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000858 return false;
859 }
860
861 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700862 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700863 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000864 return false;
865 }
866 weAllocated = true;
867 }
868
reedcf01e312015-05-23 19:14:51 -0700869 SkAutoPixmapUnlock unlocker;
870 if (bitmap->requestLock(&unlocker)) {
871 const SkPixmap& pm = unlocker.pixmap();
872 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
873 return true;
874 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000875 }
876
877 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700878 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000879 }
880 return false;
881}
reed@google.com51df9e32010-12-23 19:29:18 +0000882
bsalomon@google.comc6980972011-11-02 19:57:21 +0000883bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000884 SkIRect r = srcRect;
885 const SkISize size = this->getBaseLayerSize();
886 if (!r.intersect(0, 0, size.width(), size.height())) {
887 bitmap->reset();
888 return false;
889 }
890
reed84825042014-09-02 12:50:45 -0700891 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000892 // bitmap will already be reset.
893 return false;
894 }
895 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
896 bitmap->reset();
897 return false;
898 }
899 return true;
900}
901
reed96472de2014-12-10 09:53:42 -0800902bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000903 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000904 if (!device) {
905 return false;
906 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000907 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800908
reed96472de2014-12-10 09:53:42 -0800909 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
910 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000911 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000912 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000913
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000914 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800915 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000916}
917
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000918bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700919 SkAutoPixmapUnlock unlocker;
920 if (bitmap.requestLock(&unlocker)) {
921 const SkPixmap& pm = unlocker.pixmap();
922 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000923 }
924 return false;
925}
926
927bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
928 int x, int y) {
929 switch (origInfo.colorType()) {
930 case kUnknown_SkColorType:
931 case kIndex_8_SkColorType:
932 return false;
933 default:
934 break;
935 }
halcanary96fcdcc2015-08-27 07:41:13 -0700936 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000937 return false;
938 }
939
940 const SkISize size = this->getBaseLayerSize();
941 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
942 if (!target.intersect(0, 0, size.width(), size.height())) {
943 return false;
944 }
945
946 SkBaseDevice* device = this->getDevice();
947 if (!device) {
948 return false;
949 }
950
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000951 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700952 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000953
954 // if x or y are negative, then we have to adjust pixels
955 if (x > 0) {
956 x = 0;
957 }
958 if (y > 0) {
959 y = 0;
960 }
961 // here x,y are either 0 or negative
962 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
963
reed4af35f32014-06-27 17:47:49 -0700964 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700965 const bool completeOverwrite = info.dimensions() == size;
966 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700967
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000968 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000969 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000970}
reed@google.com51df9e32010-12-23 19:29:18 +0000971
reed@android.com8a1c16f2008-12-17 15:59:43 +0000972//////////////////////////////////////////////////////////////////////////////
973
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974void SkCanvas::updateDeviceCMCache() {
975 if (fDeviceCMDirty) {
976 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700977 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000979
halcanary96fcdcc2015-08-27 07:41:13 -0700980 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700981 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000983 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000984 do {
reedde6c5312016-09-02 12:10:07 -0700985 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700986 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987 }
988 fDeviceCMDirty = false;
989 }
990}
991
reed@android.com8a1c16f2008-12-17 15:59:43 +0000992///////////////////////////////////////////////////////////////////////////////
993
reed2ff1fce2014-12-11 07:07:37 -0800994void SkCanvas::checkForDeferredSave() {
995 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800996 this->doSave();
997 }
998}
999
reedf0090cb2014-11-26 08:55:51 -08001000int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -08001001#ifdef SK_DEBUG
1002 int count = 0;
1003 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
1004 for (;;) {
1005 const MCRec* rec = (const MCRec*)iter.next();
1006 if (!rec) {
1007 break;
1008 }
1009 count += 1 + rec->fDeferredSaveCount;
1010 }
1011 SkASSERT(count == fSaveCount);
1012#endif
1013 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001014}
1015
1016int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001017 fSaveCount += 1;
1018 fMCRec->fDeferredSaveCount += 1;
1019 return this->getSaveCount() - 1; // return our prev value
1020}
1021
1022void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001023 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001024
1025 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1026 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001027 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001028}
1029
1030void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001031 if (fMCRec->fDeferredSaveCount > 0) {
1032 SkASSERT(fSaveCount > 1);
1033 fSaveCount -= 1;
1034 fMCRec->fDeferredSaveCount -= 1;
1035 } else {
1036 // check for underflow
1037 if (fMCStack.count() > 1) {
1038 this->willRestore();
1039 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001040 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001041 this->internalRestore();
1042 this->didRestore();
1043 }
reedf0090cb2014-11-26 08:55:51 -08001044 }
1045}
1046
1047void SkCanvas::restoreToCount(int count) {
1048 // sanity check
1049 if (count < 1) {
1050 count = 1;
1051 }
mtkleinf0f14112014-12-12 08:46:25 -08001052
reedf0090cb2014-11-26 08:55:51 -08001053 int n = this->getSaveCount() - count;
1054 for (int i = 0; i < n; ++i) {
1055 this->restore();
1056 }
1057}
1058
reed2ff1fce2014-12-11 07:07:37 -08001059void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001060 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001061 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001063
reed687fa1c2015-04-07 08:00:56 -07001064 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001065}
1066
reed4960eee2015-12-18 07:09:18 -08001067bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed4960eee2015-12-18 07:09:18 -08001068 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001069}
1070
reed4960eee2015-12-18 07:09:18 -08001071bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001072 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001073 SkIRect clipBounds;
1074 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001075 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001076 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001077
reed96e657d2015-03-10 17:30:07 -07001078 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1079
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001080 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001081 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001082 if (bounds && !imageFilter->canComputeFastBounds()) {
1083 bounds = nullptr;
1084 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001085 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001086 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001087 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001089
reed96e657d2015-03-10 17:30:07 -07001090 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001091 r.roundOut(&ir);
1092 // early exit if the layer's bounds are clipped out
1093 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001094 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001095 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001096 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001097 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001098 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001099 }
1100 } else { // no user bounds, so just use the clip
1101 ir = clipBounds;
1102 }
reed180aec42015-03-11 10:39:04 -07001103 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001104
reed4960eee2015-12-18 07:09:18 -08001105 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001106 // Simplify the current clips since they will be applied properly during restore()
reed73603f32016-09-20 08:42:38 -07001107 fClipStack->clipDevRect(ir, kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001108 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001109 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001110 }
1111
1112 if (intersection) {
1113 *intersection = ir;
1114 }
1115 return true;
1116}
1117
reed4960eee2015-12-18 07:09:18 -08001118
reed4960eee2015-12-18 07:09:18 -08001119int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1120 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001121}
1122
reed70ee31b2015-12-10 13:44:45 -08001123int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001124 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1125}
1126
1127int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1128 SaveLayerRec rec(origRec);
1129 if (gIgnoreSaveLayerBounds) {
1130 rec.fBounds = nullptr;
1131 }
1132 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1133 fSaveCount += 1;
1134 this->internalSaveLayer(rec, strategy);
1135 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001136}
1137
reeda2217ef2016-07-20 06:04:34 -07001138void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1139 SkBaseDevice* dst, const SkMatrix& ctm,
1140 const SkClipStack* clipStack) {
1141 SkDraw draw;
1142 SkRasterClip rc;
1143 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1144 if (!dst->accessPixels(&draw.fDst)) {
1145 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001146 }
reeda2217ef2016-07-20 06:04:34 -07001147 draw.fMatrix = &SkMatrix::I();
1148 draw.fRC = &rc;
1149 draw.fClipStack = clipStack;
1150 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001151
1152 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001153 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001154
1155 int x = src->getOrigin().x() - dst->getOrigin().x();
1156 int y = src->getOrigin().y() - dst->getOrigin().y();
1157 auto special = src->snapSpecial();
1158 if (special) {
1159 dst->drawSpecial(draw, special.get(), x, y, p);
1160 }
robertphillips7354a4b2015-12-16 05:08:27 -08001161}
reed70ee31b2015-12-10 13:44:45 -08001162
reed129ed1c2016-02-22 06:42:31 -08001163static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1164 const SkPaint* paint) {
1165 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1166 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001167 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001168 const bool hasImageFilter = paint && paint->getImageFilter();
1169
1170 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1171 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1172 // force to L32
1173 return SkImageInfo::MakeN32(w, h, alphaType);
1174 } else {
1175 // keep the same characteristics as the prev
brianosman52ede1d2016-06-20 08:25:02 -07001176 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace()));
reed129ed1c2016-02-22 06:42:31 -08001177 }
1178}
1179
reed4960eee2015-12-18 07:09:18 -08001180void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1181 const SkRect* bounds = rec.fBounds;
1182 const SkPaint* paint = rec.fPaint;
1183 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1184
reed8c30a812016-04-20 16:36:51 -07001185 SkLazyPaint lazyP;
1186 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1187 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001188 SkMatrix remainder;
1189 SkSize scale;
1190 /*
1191 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1192 * but they do handle scaling. To accommodate this, we do the following:
1193 *
1194 * 1. Stash off the current CTM
1195 * 2. Decompose the CTM into SCALE and REMAINDER
1196 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1197 * contains the REMAINDER
1198 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1199 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1200 * of the original imagefilter, and draw that (via drawSprite)
1201 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1202 *
1203 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1204 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1205 */
reed96a04f32016-04-25 09:25:15 -07001206 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001207 stashedMatrix.decomposeScale(&scale, &remainder))
1208 {
1209 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1210 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1211 SkPaint* p = lazyP.set(*paint);
1212 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1213 SkFilterQuality::kLow_SkFilterQuality,
1214 sk_ref_sp(imageFilter)));
1215 imageFilter = p->getImageFilter();
1216 paint = p;
1217 }
reed8c30a812016-04-20 16:36:51 -07001218
junov@chromium.orga907ac32012-02-24 21:54:07 +00001219 // do this before we create the layer. We don't call the public save() since
1220 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001221 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001222
1223 fDeviceCMDirty = true;
1224
1225 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001226 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001227 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228 }
1229
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001230 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1231 // the clipRectBounds() call above?
1232 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001233 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001234 }
1235
reed4960eee2015-12-18 07:09:18 -08001236 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001237 SkPixelGeometry geo = fProps.pixelGeometry();
1238 if (paint) {
reed76033be2015-03-14 10:54:31 -07001239 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001240 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001241 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001242 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001243 }
1244 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245
robertphillips5139e502016-07-19 05:10:40 -07001246 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001247 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001248 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001249 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001250 }
reedb2db8982014-11-13 12:41:02 -08001251
robertphillips5139e502016-07-19 05:10:40 -07001252 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001253 paint);
1254
Hal Canary704cd322016-11-07 14:13:52 -05001255 sk_sp<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001256 {
reed70ee31b2015-12-10 13:44:45 -08001257 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001258 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001259 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001260 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
reedcd4051e2016-07-15 09:41:26 -07001261 preserveLCDText);
robertphillips5139e502016-07-19 05:10:40 -07001262 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1263 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001264 return;
reed61f501f2015-04-29 08:34:00 -07001265 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001266 }
robertphillips5139e502016-07-19 05:10:40 -07001267 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001268
Hal Canary704cd322016-11-07 14:13:52 -05001269 DeviceCM* layer =
1270 new DeviceCM(newDevice.get(), paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271
1272 layer->fNext = fMCRec->fTopLayer;
1273 fMCRec->fLayer = layer;
1274 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001275
1276 if (rec.fBackdrop) {
Hal Canary704cd322016-11-07 14:13:52 -05001277 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice.get(),
reeda2217ef2016-07-20 06:04:34 -07001278 fMCRec->fMatrix, this->getClipStack());
1279 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001280}
1281
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001282int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001283 if (0xFF == alpha) {
1284 return this->saveLayer(bounds, nullptr);
1285 } else {
1286 SkPaint tmpPaint;
1287 tmpPaint.setAlpha(alpha);
1288 return this->saveLayer(bounds, &tmpPaint);
1289 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001290}
1291
reed@android.com8a1c16f2008-12-17 15:59:43 +00001292void SkCanvas::internalRestore() {
1293 SkASSERT(fMCStack.count() != 0);
1294
1295 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296
reed687fa1c2015-04-07 08:00:56 -07001297 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001298
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001299 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300 DeviceCM* layer = fMCRec->fLayer; // may be null
1301 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001302 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303
1304 // now do the normal restore()
1305 fMCRec->~MCRec(); // balanced in save()
1306 fMCStack.pop_back();
1307 fMCRec = (MCRec*)fMCStack.back();
1308
1309 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1310 since if we're being recorded, we don't want to record this (the
1311 recorder will have already recorded the restore).
1312 */
bsalomon49f085d2014-09-05 13:34:00 -07001313 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001315 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001316 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001317 // restore what we smashed in internalSaveLayer
1318 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001319 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001321 delete layer;
reedb679ca82015-04-07 04:40:48 -07001322 } else {
1323 // we're at the root
reeda499f902015-05-01 09:34:31 -07001324 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001325 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001326 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001327 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001328 }
msarettfbfa2582016-08-12 08:29:08 -07001329
1330 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001331 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001332 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1333 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334}
1335
reede8f30622016-03-23 18:59:25 -07001336sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001337 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001338 props = &fProps;
1339 }
1340 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001341}
1342
reede8f30622016-03-23 18:59:25 -07001343sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001344 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001345 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001346}
1347
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001348SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001349 return this->onImageInfo();
1350}
1351
1352SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001353 SkBaseDevice* dev = this->getDevice();
1354 if (dev) {
1355 return dev->imageInfo();
1356 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001357 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001358 }
1359}
1360
brianosman898235c2016-04-06 07:38:23 -07001361bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001362 return this->onGetProps(props);
1363}
1364
1365bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001366 SkBaseDevice* dev = this->getDevice();
1367 if (dev) {
1368 if (props) {
1369 *props = fProps;
1370 }
1371 return true;
1372 } else {
1373 return false;
1374 }
1375}
1376
reed6ceeebd2016-03-09 14:26:26 -08001377bool SkCanvas::peekPixels(SkPixmap* pmap) {
1378 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001379}
1380
reed884e97c2015-05-26 11:31:54 -07001381bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001382 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001383 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001384}
1385
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001386void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001387 SkPixmap pmap;
1388 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001389 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001390 }
1391 if (info) {
1392 *info = pmap.info();
1393 }
1394 if (rowBytes) {
1395 *rowBytes = pmap.rowBytes();
1396 }
1397 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001398 *origin = this->getTopDevice(false)->getOrigin();
1399 }
reed884e97c2015-05-26 11:31:54 -07001400 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001401}
1402
reed884e97c2015-05-26 11:31:54 -07001403bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001404 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001405 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001406}
1407
reed@android.com8a1c16f2008-12-17 15:59:43 +00001408/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409
reed7503d602016-07-15 14:23:29 -07001410void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001411 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001412 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413 paint = &tmp;
1414 }
reed@google.com4b226022011-01-11 18:32:13 +00001415
reed@google.com8926b162012-03-23 15:36:36 +00001416 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001417
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001419 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001420 paint = &looper.paint();
1421 SkImageFilter* filter = paint->getImageFilter();
1422 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
Robert Phillips833dcf42016-11-18 08:44:13 -05001423 if (filter) {
1424 sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial();
1425 if (specialImage) {
1426 dstDev->drawSpecial(iter, specialImage.get(), pos.x(), pos.y(), *paint);
1427 }
reed@google.com76dd2772012-01-05 21:15:07 +00001428 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001429 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001430 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001431 }
reeda2217ef2016-07-20 06:04:34 -07001432
reed@google.com4e2b3d32011-04-07 14:18:59 +00001433 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001434}
1435
reed32704672015-12-16 08:27:10 -08001436/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001437
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001438void SkCanvas::translate(SkScalar dx, SkScalar dy) {
reedfe69b502016-09-12 06:31:48 -07001439 if (dx || dy) {
1440 this->checkForDeferredSave();
1441 fDeviceCMDirty = true;
1442 fMCRec->fMatrix.preTranslate(dx,dy);
mtkleincbdf0072016-08-19 09:05:27 -07001443
reedfe69b502016-09-12 06:31:48 -07001444 // Translate shouldn't affect the is-scale-translateness of the matrix.
1445 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
mtkleincbdf0072016-08-19 09:05:27 -07001446
reedfe69b502016-09-12 06:31:48 -07001447 this->didTranslate(dx,dy);
1448 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001449}
1450
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001451void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001452 SkMatrix m;
1453 m.setScale(sx, sy);
1454 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001455}
1456
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001457void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001458 SkMatrix m;
1459 m.setRotate(degrees);
1460 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001461}
1462
bungeman7438bfc2016-07-12 15:01:19 -07001463void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1464 SkMatrix m;
1465 m.setRotate(degrees, px, py);
1466 this->concat(m);
1467}
1468
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001469void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001470 SkMatrix m;
1471 m.setSkew(sx, sy);
1472 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001473}
1474
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001475void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001476 if (matrix.isIdentity()) {
1477 return;
1478 }
1479
reed2ff1fce2014-12-11 07:07:37 -08001480 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001481 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001482 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001483 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001484 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001485}
1486
reed8c30a812016-04-20 16:36:51 -07001487void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001489 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001490 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001491}
1492
1493void SkCanvas::setMatrix(const SkMatrix& matrix) {
1494 this->checkForDeferredSave();
1495 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001496 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001497}
1498
reed@android.com8a1c16f2008-12-17 15:59:43 +00001499void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001500 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501}
1502
vjiaoblack95302da2016-07-21 10:25:54 -07001503#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001504void SkCanvas::translateZ(SkScalar z) {
1505 this->checkForDeferredSave();
1506 this->fMCRec->fCurDrawDepth += z;
1507 this->didTranslateZ(z);
1508}
1509
1510SkScalar SkCanvas::getZ() const {
1511 return this->fMCRec->fCurDrawDepth;
1512}
1513
vjiaoblack95302da2016-07-21 10:25:54 -07001514void SkCanvas::setLights(sk_sp<SkLights> lights) {
1515 this->fLights = lights;
1516}
1517
1518sk_sp<SkLights> SkCanvas::getLights() const {
1519 return this->fLights;
1520}
1521#endif
1522
reed@android.com8a1c16f2008-12-17 15:59:43 +00001523//////////////////////////////////////////////////////////////////////////////
1524
reed73603f32016-09-20 08:42:38 -07001525void SkCanvas::clipRect(const SkRect& rect, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001526 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001527 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1528 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001529}
1530
reed73603f32016-09-20 08:42:38 -07001531void SkCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001532 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reedc64eff52015-11-21 12:39:45 -08001533 AutoValidateClip avc(this);
Brian Salomona3b45d42016-10-03 11:36:16 -04001534 fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA);
1535 fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1536 isAA);
reedc64eff52015-11-21 12:39:45 -08001537 fDeviceCMDirty = true;
msarettfbfa2582016-08-12 08:29:08 -07001538 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001539}
1540
reed73603f32016-09-20 08:42:38 -07001541void SkCanvas::clipRRect(const SkRRect& rrect, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001542 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001543 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001544 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001545 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1546 } else {
1547 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001548 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001549}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001550
reed73603f32016-09-20 08:42:38 -07001551void SkCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001552 AutoValidateClip avc(this);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001553
Brian Salomona3b45d42016-10-03 11:36:16 -04001554 fDeviceCMDirty = true;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001555
Brian Salomona3b45d42016-10-03 11:36:16 -04001556 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1557 fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA);
1558 fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1559 isAA);
1560 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1561 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001562}
1563
reed73603f32016-09-20 08:42:38 -07001564void SkCanvas::clipPath(const SkPath& path, ClipOp op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001565 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001566 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001567
1568 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1569 SkRect r;
1570 if (path.isRect(&r)) {
1571 this->onClipRect(r, op, edgeStyle);
1572 return;
1573 }
1574 SkRRect rrect;
1575 if (path.isOval(&r)) {
1576 rrect.setOval(r);
1577 this->onClipRRect(rrect, op, edgeStyle);
1578 return;
1579 }
1580 if (path.isRRect(&rrect)) {
1581 this->onClipRRect(rrect, op, edgeStyle);
1582 return;
1583 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001584 }
robertphillips39f05382015-11-24 09:30:12 -08001585
1586 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001587}
1588
reed73603f32016-09-20 08:42:38 -07001589void SkCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001590 AutoValidateClip avc(this);
1591
reed@android.com8a1c16f2008-12-17 15:59:43 +00001592 fDeviceCMDirty = true;
Brian Salomona3b45d42016-10-03 11:36:16 -04001593 bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001594
Brian Salomona3b45d42016-10-03 11:36:16 -04001595 fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001596
Brian Salomona3b45d42016-10-03 11:36:16 -04001597 const SkPath* rasterClipPath = &path;
1598 const SkMatrix* matrix = &fMCRec->fMatrix;
1599 SkPath tempPath;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001600 if (fAllowSimplifyClip) {
Brian Salomona3b45d42016-10-03 11:36:16 -04001601 isAA = getClipStack()->asPath(&tempPath);
1602 rasterClipPath = &tempPath;
1603 matrix = &SkMatrix::I();
reed73603f32016-09-20 08:42:38 -07001604 op = kReplace_Op;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001605 }
Brian Salomona3b45d42016-10-03 11:36:16 -04001606 fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op,
1607 isAA);
msarettfbfa2582016-08-12 08:29:08 -07001608 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001609}
1610
reed73603f32016-09-20 08:42:38 -07001611void SkCanvas::clipRegion(const SkRegion& rgn, ClipOp op) {
reed2ff1fce2014-12-11 07:07:37 -08001612 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001613 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001614}
1615
reed73603f32016-09-20 08:42:38 -07001616void SkCanvas::onClipRegion(const SkRegion& rgn, ClipOp op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001617 AutoValidateClip avc(this);
1618
reed@android.com8a1c16f2008-12-17 15:59:43 +00001619 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001620
reed@google.com5c3d1472011-02-22 19:12:23 +00001621 // todo: signal fClipStack that we have a region, and therefore (I guess)
1622 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001623 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001624
reed73603f32016-09-20 08:42:38 -07001625 fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op);
msarettfbfa2582016-08-12 08:29:08 -07001626 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001627}
1628
reed@google.com819c9212011-02-23 18:56:55 +00001629#ifdef SK_DEBUG
1630void SkCanvas::validateClip() const {
1631 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001632 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001633 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001634 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001635 return;
1636 }
1637
reed@google.com819c9212011-02-23 18:56:55 +00001638 SkIRect ir;
1639 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001640 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001641
reed687fa1c2015-04-07 08:00:56 -07001642 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001643 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001644 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001645 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001646 case SkClipStack::Element::kRect_Type:
1647 element->getRect().round(&ir);
reed73603f32016-09-20 08:42:38 -07001648 tmpClip.op(ir, (SkRegion::Op)element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001649 break;
1650 case SkClipStack::Element::kEmpty_Type:
1651 tmpClip.setEmpty();
1652 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001653 default: {
1654 SkPath path;
1655 element->asPath(&path);
Brian Salomona3b45d42016-10-03 11:36:16 -04001656 tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(),
1657 (SkRegion::Op)element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001658 break;
1659 }
reed@google.com819c9212011-02-23 18:56:55 +00001660 }
1661 }
reed@google.com819c9212011-02-23 18:56:55 +00001662}
1663#endif
1664
reed@google.com90c07ea2012-04-13 13:50:27 +00001665void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001666 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001667 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001668
halcanary96fcdcc2015-08-27 07:41:13 -07001669 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001670 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001671 }
1672}
1673
reed@google.com5c3d1472011-02-22 19:12:23 +00001674///////////////////////////////////////////////////////////////////////////////
1675
reed@google.com754de5f2014-02-24 19:38:20 +00001676bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001677 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001678}
1679
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001680bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001681 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001682}
1683
msarettfbfa2582016-08-12 08:29:08 -07001684static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1685#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1686 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1687 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1688 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1689 return 0xF != _mm_movemask_ps(mask);
1690#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1691 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1692 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1693 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1694 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1695#else
1696 SkRect devRectAsRect;
1697 SkRect devClipAsRect;
1698 devRect.store(&devRectAsRect.fLeft);
1699 devClip.store(&devClipAsRect.fLeft);
1700 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1701#endif
1702}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001703
msarettfbfa2582016-08-12 08:29:08 -07001704// It's important for this function to not be inlined. Otherwise the compiler will share code
1705// between the fast path and the slow path, resulting in two slow paths.
1706static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1707 const SkMatrix& matrix) {
1708 SkRect deviceRect;
1709 matrix.mapRect(&deviceRect, src);
1710 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1711}
1712
1713bool SkCanvas::quickReject(const SkRect& src) const {
1714#ifdef SK_DEBUG
1715 // Verify that fDeviceClipBounds are set properly.
1716 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001717 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001718 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001719 } else {
msarettfbfa2582016-08-12 08:29:08 -07001720 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001721 }
msarettfbfa2582016-08-12 08:29:08 -07001722
msarett9637ea92016-08-18 14:03:30 -07001723 // Verify that fIsScaleTranslate is set properly.
1724 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001725#endif
1726
msarett9637ea92016-08-18 14:03:30 -07001727 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001728 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1729 }
1730
1731 // We inline the implementation of mapScaleTranslate() for the fast path.
1732 float sx = fMCRec->fMatrix.getScaleX();
1733 float sy = fMCRec->fMatrix.getScaleY();
1734 float tx = fMCRec->fMatrix.getTranslateX();
1735 float ty = fMCRec->fMatrix.getTranslateY();
1736 Sk4f scale(sx, sy, sx, sy);
1737 Sk4f trans(tx, ty, tx, ty);
1738
1739 // Apply matrix.
1740 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1741
1742 // Make sure left < right, top < bottom.
1743 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1744 Sk4f min = Sk4f::Min(ltrb, rblt);
1745 Sk4f max = Sk4f::Max(ltrb, rblt);
1746 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1747 // ARM this sequence generates the fastest (a single instruction).
1748 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1749
1750 // Check if the device rect is NaN or outside the clip.
1751 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001752}
1753
reed@google.com3b3e8952012-08-16 20:53:31 +00001754bool SkCanvas::quickReject(const SkPath& path) const {
1755 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001756}
1757
reed@google.com3b3e8952012-08-16 20:53:31 +00001758bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001759 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001760 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001761 return false;
1762 }
1763
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001764 SkMatrix inverse;
1765 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001766 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001767 if (bounds) {
1768 bounds->setEmpty();
1769 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001770 return false;
1771 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001772
bsalomon49f085d2014-09-05 13:34:00 -07001773 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001774 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001775 // adjust it outwards in case we are antialiasing
1776 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001777
reed@google.com8f4d2302013-12-17 16:44:46 +00001778 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1779 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001780 inverse.mapRect(bounds, r);
1781 }
1782 return true;
1783}
1784
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001785bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001786 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001787 if (clip.isEmpty()) {
1788 if (bounds) {
1789 bounds->setEmpty();
1790 }
1791 return false;
1792 }
1793
bsalomon49f085d2014-09-05 13:34:00 -07001794 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001795 *bounds = clip.getBounds();
1796 }
1797 return true;
1798}
1799
reed@android.com8a1c16f2008-12-17 15:59:43 +00001800const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001801 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001802}
1803
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001804const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001805 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001806}
1807
Brian Osman11052242016-10-27 14:47:55 -04001808GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001809 SkBaseDevice* dev = this->getTopDevice();
Brian Osman11052242016-10-27 14:47:55 -04001810 return dev ? dev->accessRenderTargetContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001811}
1812
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001813GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001814 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001815 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001816}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001817
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001818void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1819 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001820 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001821 if (outer.isEmpty()) {
1822 return;
1823 }
1824 if (inner.isEmpty()) {
1825 this->drawRRect(outer, paint);
1826 return;
1827 }
1828
1829 // We don't have this method (yet), but technically this is what we should
1830 // be able to assert...
1831 // SkASSERT(outer.contains(inner));
1832 //
1833 // For now at least check for containment of bounds
1834 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1835
1836 this->onDrawDRRect(outer, inner, paint);
1837}
1838
reed41af9662015-01-05 07:49:08 -08001839// These need to stop being virtual -- clients need to override the onDraw... versions
1840
1841void SkCanvas::drawPaint(const SkPaint& paint) {
1842 this->onDrawPaint(paint);
1843}
1844
1845void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1846 this->onDrawRect(r, paint);
1847}
1848
msarettdca352e2016-08-26 06:37:45 -07001849void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1850 if (region.isEmpty()) {
1851 return;
1852 }
1853
1854 if (region.isRect()) {
1855 return this->drawIRect(region.getBounds(), paint);
1856 }
1857
1858 this->onDrawRegion(region, paint);
1859}
1860
reed41af9662015-01-05 07:49:08 -08001861void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1862 this->onDrawOval(r, paint);
1863}
1864
1865void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1866 this->onDrawRRect(rrect, paint);
1867}
1868
1869void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1870 this->onDrawPoints(mode, count, pts, paint);
1871}
1872
1873void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
Mike Reed7d954ad2016-10-28 15:42:34 -04001874 const SkPoint texs[], const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08001875 const uint16_t indices[], int indexCount, const SkPaint& paint) {
Mike Reedfaba3712016-11-03 14:45:31 -04001876 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, bmode,
reed41af9662015-01-05 07:49:08 -08001877 indices, indexCount, paint);
1878}
1879
1880void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1881 this->onDrawPath(path, paint);
1882}
1883
reeda85d4d02015-05-06 12:56:48 -07001884void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001885 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001886 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001887}
1888
reede47829b2015-08-06 10:02:53 -07001889void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1890 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001891 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001892 if (dst.isEmpty() || src.isEmpty()) {
1893 return;
1894 }
1895 this->onDrawImageRect(image, &src, dst, paint, constraint);
1896}
reed41af9662015-01-05 07:49:08 -08001897
reed84984ef2015-07-17 07:09:43 -07001898void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1899 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001900 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001901 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001902}
1903
reede47829b2015-08-06 10:02:53 -07001904void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1905 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08001906 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07001907 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1908 constraint);
1909}
reede47829b2015-08-06 10:02:53 -07001910
reed4c21dc52015-06-25 12:32:03 -07001911void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1912 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001913 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07001914 if (dst.isEmpty()) {
1915 return;
1916 }
msarett552bca92016-08-03 06:53:26 -07001917 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
1918 this->onDrawImageNine(image, center, dst, paint);
1919 } else {
reede47829b2015-08-06 10:02:53 -07001920 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001921 }
reed4c21dc52015-06-25 12:32:03 -07001922}
1923
msarett16882062016-08-16 09:31:08 -07001924void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
1925 const SkPaint* paint) {
1926 RETURN_ON_NULL(image);
1927 if (dst.isEmpty()) {
1928 return;
1929 }
msarett71df2d72016-09-30 12:41:42 -07001930
1931 SkIRect bounds;
1932 Lattice latticePlusBounds = lattice;
1933 if (!latticePlusBounds.fBounds) {
1934 bounds = SkIRect::MakeWH(image->width(), image->height());
1935 latticePlusBounds.fBounds = &bounds;
1936 }
1937
1938 if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
1939 this->onDrawImageLattice(image, latticePlusBounds, dst, paint);
msarett16882062016-08-16 09:31:08 -07001940 } else {
1941 this->drawImageRect(image, dst, paint);
1942 }
1943}
1944
reed41af9662015-01-05 07:49:08 -08001945void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001946 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001947 return;
1948 }
reed41af9662015-01-05 07:49:08 -08001949 this->onDrawBitmap(bitmap, dx, dy, paint);
1950}
1951
reede47829b2015-08-06 10:02:53 -07001952void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001953 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001954 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001955 return;
1956 }
reede47829b2015-08-06 10:02:53 -07001957 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001958}
1959
reed84984ef2015-07-17 07:09:43 -07001960void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1961 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001962 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001963}
1964
reede47829b2015-08-06 10:02:53 -07001965void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1966 SrcRectConstraint constraint) {
1967 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1968 constraint);
1969}
reede47829b2015-08-06 10:02:53 -07001970
reed41af9662015-01-05 07:49:08 -08001971void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1972 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001973 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001974 return;
1975 }
msarett552bca92016-08-03 06:53:26 -07001976 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
1977 this->onDrawBitmapNine(bitmap, center, dst, paint);
1978 } else {
reeda5517e22015-07-14 10:54:12 -07001979 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001980 }
reed41af9662015-01-05 07:49:08 -08001981}
1982
msarettc573a402016-08-02 08:05:56 -07001983void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
1984 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07001985 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07001986 return;
1987 }
msarett71df2d72016-09-30 12:41:42 -07001988
1989 SkIRect bounds;
1990 Lattice latticePlusBounds = lattice;
1991 if (!latticePlusBounds.fBounds) {
1992 bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1993 latticePlusBounds.fBounds = &bounds;
1994 }
1995
1996 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) {
1997 this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint);
msarett552bca92016-08-03 06:53:26 -07001998 } else {
msarett16882062016-08-16 09:31:08 -07001999 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002000 }
msarettc573a402016-08-02 08:05:56 -07002001}
2002
reed71c3c762015-06-24 10:29:17 -07002003void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reed7d954ad2016-10-28 15:42:34 -04002004 const SkColor colors[], int count, SkBlendMode mode,
reed71c3c762015-06-24 10:29:17 -07002005 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002006 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002007 if (count <= 0) {
2008 return;
2009 }
2010 SkASSERT(atlas);
reed71c3c762015-06-24 10:29:17 -07002011 SkASSERT(tex);
Mike Reedfaba3712016-11-03 14:45:31 -04002012 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
reed71c3c762015-06-24 10:29:17 -07002013}
2014
reedf70b5312016-03-04 16:36:20 -08002015void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2016 if (key) {
2017 this->onDrawAnnotation(rect, key, value);
2018 }
2019}
2020
reede47829b2015-08-06 10:02:53 -07002021void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2022 const SkPaint* paint, SrcRectConstraint constraint) {
2023 if (src) {
2024 this->drawImageRect(image, *src, dst, paint, constraint);
2025 } else {
2026 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2027 dst, paint, constraint);
2028 }
2029}
2030void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2031 const SkPaint* paint, SrcRectConstraint constraint) {
2032 if (src) {
2033 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2034 } else {
2035 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2036 dst, paint, constraint);
2037 }
2038}
2039
tomhudsoncb3bd182016-05-18 07:24:16 -07002040void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2041 SkIRect layer_bounds = this->getTopLayerBounds();
2042 if (matrix) {
2043 *matrix = this->getTotalMatrix();
2044 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2045 }
2046 if (clip_bounds) {
2047 this->getClipDeviceBounds(clip_bounds);
2048 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2049 }
2050}
2051
reed@android.com8a1c16f2008-12-17 15:59:43 +00002052//////////////////////////////////////////////////////////////////////////////
2053// These are the virtual drawing methods
2054//////////////////////////////////////////////////////////////////////////////
2055
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002056void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002057 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002058 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2059 }
2060}
2061
reed41af9662015-01-05 07:49:08 -08002062void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002063 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002064 this->internalDrawPaint(paint);
2065}
2066
2067void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002068 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002069
2070 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002071 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002072 }
2073
reed@google.com4e2b3d32011-04-07 14:18:59 +00002074 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002075}
2076
reed41af9662015-01-05 07:49:08 -08002077void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2078 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002079 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002080 if ((long)count <= 0) {
2081 return;
2082 }
2083
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002084 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002085 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002086 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002087 // special-case 2 points (common for drawing a single line)
2088 if (2 == count) {
2089 r.set(pts[0], pts[1]);
2090 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002091 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002092 }
senorblanco87e066e2015-10-28 11:23:36 -07002093 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2094 return;
2095 }
2096 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002097 }
reed@google.coma584aed2012-05-16 14:06:02 +00002098
halcanary96fcdcc2015-08-27 07:41:13 -07002099 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002100
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002101 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002102
reed@android.com8a1c16f2008-12-17 15:59:43 +00002103 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002104 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002105 }
reed@google.com4b226022011-01-11 18:32:13 +00002106
reed@google.com4e2b3d32011-04-07 14:18:59 +00002107 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002108}
2109
reed4a167172016-08-18 17:15:25 -07002110static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2111 return ((intptr_t)paint.getImageFilter() |
2112#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2113 (intptr_t)canvas->getDrawFilter() |
2114#endif
2115 (intptr_t)paint.getLooper() ) != 0;
2116}
2117
reed41af9662015-01-05 07:49:08 -08002118void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002119 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002120 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002121 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002122 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002123 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2124 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2125 SkRect tmp(r);
2126 tmp.sort();
2127
senorblanco87e066e2015-10-28 11:23:36 -07002128 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2129 return;
2130 }
2131 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002132 }
reed@google.com4b226022011-01-11 18:32:13 +00002133
reed4a167172016-08-18 17:15:25 -07002134 if (needs_autodrawlooper(this, paint)) {
2135 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002136
reed4a167172016-08-18 17:15:25 -07002137 while (iter.next()) {
2138 iter.fDevice->drawRect(iter, r, looper.paint());
2139 }
2140
2141 LOOPER_END
2142 } else {
2143 this->predrawNotify(bounds, &paint, false);
2144 SkDrawIter iter(this);
2145 while (iter.next()) {
2146 iter.fDevice->drawRect(iter, r, paint);
2147 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002148 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002149}
2150
msarett44df6512016-08-25 13:54:30 -07002151void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2152 SkRect storage;
2153 SkRect regionRect = SkRect::Make(region.getBounds());
2154 const SkRect* bounds = nullptr;
2155 if (paint.canComputeFastBounds()) {
2156 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2157 return;
2158 }
2159 bounds = &regionRect;
2160 }
2161
2162 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2163
2164 while (iter.next()) {
2165 iter.fDevice->drawRegion(iter, region, looper.paint());
2166 }
2167
2168 LOOPER_END
2169}
2170
reed41af9662015-01-05 07:49:08 -08002171void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002172 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002173 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002174 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002175 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002176 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2177 return;
2178 }
2179 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002180 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002181
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002182 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002183
2184 while (iter.next()) {
2185 iter.fDevice->drawOval(iter, oval, looper.paint());
2186 }
2187
2188 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002189}
2190
bsalomonac3aa242016-08-19 11:25:19 -07002191void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2192 SkScalar sweepAngle, bool useCenter,
2193 const SkPaint& paint) {
2194 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2195 const SkRect* bounds = nullptr;
2196 if (paint.canComputeFastBounds()) {
2197 SkRect storage;
2198 // Note we're using the entire oval as the bounds.
2199 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2200 return;
2201 }
2202 bounds = &oval;
2203 }
2204
2205 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2206
2207 while (iter.next()) {
2208 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2209 }
2210
2211 LOOPER_END
2212}
2213
reed41af9662015-01-05 07:49:08 -08002214void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002215 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002216 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002217 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002218 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002219 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2220 return;
2221 }
2222 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002223 }
2224
2225 if (rrect.isRect()) {
2226 // call the non-virtual version
2227 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002228 return;
2229 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002230 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002231 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2232 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002233 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002234
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002235 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002236
2237 while (iter.next()) {
2238 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2239 }
2240
2241 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002242}
2243
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002244void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2245 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002246 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002247 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002248 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002249 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2250 return;
2251 }
2252 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002253 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002254
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002255 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002256
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002257 while (iter.next()) {
2258 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2259 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002260
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002261 LOOPER_END
2262}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002263
reed41af9662015-01-05 07:49:08 -08002264void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002265 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002266 if (!path.isFinite()) {
2267 return;
2268 }
2269
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002270 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002271 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002272 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002273 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002274 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2275 return;
2276 }
2277 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002278 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002279
2280 const SkRect& r = path.getBounds();
2281 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002282 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002283 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002284 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002285 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002286 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002287
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002288 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002289
2290 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002291 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002292 }
2293
reed@google.com4e2b3d32011-04-07 14:18:59 +00002294 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002295}
2296
reed262a71b2015-12-05 13:07:27 -08002297bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002298 if (!paint.getImageFilter()) {
2299 return false;
2300 }
2301
2302 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002303 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002304 return false;
2305 }
2306
2307 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2308 // Once we can filter and the filter will return a result larger than itself, we should be
2309 // able to remove this constraint.
2310 // skbug.com/4526
2311 //
2312 SkPoint pt;
2313 ctm.mapXY(x, y, &pt);
2314 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2315 return ir.contains(fMCRec->fRasterClip.getBounds());
2316}
2317
reeda85d4d02015-05-06 12:56:48 -07002318void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002319 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002320 SkRect bounds = SkRect::MakeXYWH(x, y,
2321 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002322 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002323 SkRect tmp = bounds;
2324 if (paint) {
2325 paint->computeFastBounds(tmp, &tmp);
2326 }
2327 if (this->quickReject(tmp)) {
2328 return;
2329 }
reeda85d4d02015-05-06 12:56:48 -07002330 }
halcanary9d524f22016-03-29 09:03:52 -07002331
reeda85d4d02015-05-06 12:56:48 -07002332 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002333 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002334 paint = lazy.init();
2335 }
reed262a71b2015-12-05 13:07:27 -08002336
reeda2217ef2016-07-20 06:04:34 -07002337 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002338 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2339 *paint);
2340 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002341 special = this->getDevice()->makeSpecial(image);
2342 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002343 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002344 }
2345 }
2346
reed262a71b2015-12-05 13:07:27 -08002347 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2348
reeda85d4d02015-05-06 12:56:48 -07002349 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002350 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002351 if (special) {
2352 SkPoint pt;
2353 iter.fMatrix->mapXY(x, y, &pt);
2354 iter.fDevice->drawSpecial(iter, special.get(),
2355 SkScalarRoundToInt(pt.fX),
2356 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002357 } else {
2358 iter.fDevice->drawImage(iter, image, x, y, pnt);
2359 }
reeda85d4d02015-05-06 12:56:48 -07002360 }
halcanary9d524f22016-03-29 09:03:52 -07002361
reeda85d4d02015-05-06 12:56:48 -07002362 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002363}
2364
reed41af9662015-01-05 07:49:08 -08002365void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002366 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002367 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002368 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002369 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002370 if (paint) {
2371 paint->computeFastBounds(dst, &storage);
2372 }
2373 if (this->quickReject(storage)) {
2374 return;
2375 }
reeda85d4d02015-05-06 12:56:48 -07002376 }
2377 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002378 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002379 paint = lazy.init();
2380 }
halcanary9d524f22016-03-29 09:03:52 -07002381
senorblancoc41e7e12015-12-07 12:51:30 -08002382 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002383 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002384
reeda85d4d02015-05-06 12:56:48 -07002385 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002386 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002387 }
halcanary9d524f22016-03-29 09:03:52 -07002388
reeda85d4d02015-05-06 12:56:48 -07002389 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002390}
2391
reed41af9662015-01-05 07:49:08 -08002392void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002393 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002394 SkDEBUGCODE(bitmap.validate();)
2395
reed33366972015-10-08 09:22:02 -07002396 if (bitmap.drawsNothing()) {
2397 return;
2398 }
2399
2400 SkLazyPaint lazy;
2401 if (nullptr == paint) {
2402 paint = lazy.init();
2403 }
2404
2405 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2406
2407 SkRect storage;
2408 const SkRect* bounds = nullptr;
2409 if (paint->canComputeFastBounds()) {
2410 bitmap.getBounds(&storage);
2411 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002412 SkRect tmp = storage;
2413 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2414 return;
2415 }
2416 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002417 }
reed@google.com4b226022011-01-11 18:32:13 +00002418
reeda2217ef2016-07-20 06:04:34 -07002419 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002420 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2421 *paint);
2422 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002423 special = this->getDevice()->makeSpecial(bitmap);
2424 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002425 drawAsSprite = false;
2426 }
2427 }
2428
reed262a71b2015-12-05 13:07:27 -08002429 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002430
2431 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002432 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002433 if (special) {
reed262a71b2015-12-05 13:07:27 -08002434 SkPoint pt;
2435 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002436 iter.fDevice->drawSpecial(iter, special.get(),
2437 SkScalarRoundToInt(pt.fX),
2438 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002439 } else {
2440 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2441 }
reed33366972015-10-08 09:22:02 -07002442 }
msarettfbfa2582016-08-12 08:29:08 -07002443
reed33366972015-10-08 09:22:02 -07002444 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002445}
2446
reed@google.com9987ec32011-09-07 11:57:52 +00002447// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002448void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002449 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002450 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002451 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002452 return;
2453 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002454
halcanary96fcdcc2015-08-27 07:41:13 -07002455 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002456 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002457 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2458 return;
2459 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002460 }
reed@google.com3d608122011-11-21 15:16:16 +00002461
reed@google.com33535f32012-09-25 15:37:50 +00002462 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002463 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002464 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002465 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002466
senorblancoc41e7e12015-12-07 12:51:30 -08002467 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002468 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002469
reed@google.com33535f32012-09-25 15:37:50 +00002470 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002471 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002472 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002473
reed@google.com33535f32012-09-25 15:37:50 +00002474 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002475}
2476
reed41af9662015-01-05 07:49:08 -08002477void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002478 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002479 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002480 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002481 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002482}
2483
reed4c21dc52015-06-25 12:32:03 -07002484void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2485 const SkPaint* paint) {
2486 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002487
halcanary96fcdcc2015-08-27 07:41:13 -07002488 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002489 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002490 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2491 return;
2492 }
reed@google.com3d608122011-11-21 15:16:16 +00002493 }
halcanary9d524f22016-03-29 09:03:52 -07002494
reed4c21dc52015-06-25 12:32:03 -07002495 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002496 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002497 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002498 }
halcanary9d524f22016-03-29 09:03:52 -07002499
senorblancoc41e7e12015-12-07 12:51:30 -08002500 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002501
reed4c21dc52015-06-25 12:32:03 -07002502 while (iter.next()) {
2503 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002504 }
halcanary9d524f22016-03-29 09:03:52 -07002505
reed4c21dc52015-06-25 12:32:03 -07002506 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002507}
2508
reed41af9662015-01-05 07:49:08 -08002509void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2510 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002511 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002512 SkDEBUGCODE(bitmap.validate();)
2513
halcanary96fcdcc2015-08-27 07:41:13 -07002514 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002515 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002516 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2517 return;
2518 }
reed4c21dc52015-06-25 12:32:03 -07002519 }
halcanary9d524f22016-03-29 09:03:52 -07002520
reed4c21dc52015-06-25 12:32:03 -07002521 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002522 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002523 paint = lazy.init();
2524 }
halcanary9d524f22016-03-29 09:03:52 -07002525
senorblancoc41e7e12015-12-07 12:51:30 -08002526 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002527
reed4c21dc52015-06-25 12:32:03 -07002528 while (iter.next()) {
2529 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2530 }
halcanary9d524f22016-03-29 09:03:52 -07002531
reed4c21dc52015-06-25 12:32:03 -07002532 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002533}
2534
msarett16882062016-08-16 09:31:08 -07002535void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2536 const SkPaint* paint) {
2537 if (nullptr == paint || paint->canComputeFastBounds()) {
2538 SkRect storage;
2539 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2540 return;
2541 }
2542 }
2543
2544 SkLazyPaint lazy;
2545 if (nullptr == paint) {
2546 paint = lazy.init();
2547 }
2548
2549 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2550
2551 while (iter.next()) {
2552 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2553 }
2554
2555 LOOPER_END
2556}
2557
2558void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2559 const SkRect& dst, const SkPaint* paint) {
2560 if (nullptr == paint || paint->canComputeFastBounds()) {
2561 SkRect storage;
2562 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2563 return;
2564 }
2565 }
2566
2567 SkLazyPaint lazy;
2568 if (nullptr == paint) {
2569 paint = lazy.init();
2570 }
2571
2572 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2573
2574 while (iter.next()) {
2575 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2576 }
2577
2578 LOOPER_END
2579}
2580
reed@google.comf67e4cf2011-03-15 20:56:58 +00002581class SkDeviceFilteredPaint {
2582public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002583 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002584 uint32_t filteredFlags = device->filterTextFlags(paint);
2585 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002586 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002587 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002588 fPaint = newPaint;
2589 } else {
2590 fPaint = &paint;
2591 }
2592 }
2593
reed@google.comf67e4cf2011-03-15 20:56:58 +00002594 const SkPaint& paint() const { return *fPaint; }
2595
2596private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002597 const SkPaint* fPaint;
2598 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002599};
2600
bungeman@google.com52c748b2011-08-22 21:30:43 +00002601void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2602 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002603 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002604 draw.fDevice->drawRect(draw, r, paint);
2605 } else {
2606 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002607 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002608 draw.fDevice->drawRect(draw, r, p);
2609 }
2610}
2611
2612void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2613 const char text[], size_t byteLength,
2614 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002615 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002616
2617 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002618 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002619 draw.fRC->isEmpty() ||
reed374772b2016-10-05 17:33:02 -07002620 (paint.getAlpha() == 0 && paint.isSrcOver())) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002621 return;
2622 }
2623
2624 SkScalar width = 0;
2625 SkPoint start;
2626
2627 start.set(0, 0); // to avoid warning
2628 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2629 SkPaint::kStrikeThruText_Flag)) {
2630 width = paint.measureText(text, byteLength);
2631
2632 SkScalar offsetX = 0;
2633 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2634 offsetX = SkScalarHalf(width);
2635 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2636 offsetX = width;
2637 }
2638 start.set(x - offsetX, y);
2639 }
2640
2641 if (0 == width) {
2642 return;
2643 }
2644
2645 uint32_t flags = paint.getFlags();
2646
2647 if (flags & (SkPaint::kUnderlineText_Flag |
2648 SkPaint::kStrikeThruText_Flag)) {
2649 SkScalar textSize = paint.getTextSize();
2650 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2651 SkRect r;
2652
2653 r.fLeft = start.fX;
2654 r.fRight = start.fX + width;
2655
2656 if (flags & SkPaint::kUnderlineText_Flag) {
2657 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2658 start.fY);
2659 r.fTop = offset;
2660 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002661 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002662 }
2663 if (flags & SkPaint::kStrikeThruText_Flag) {
2664 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2665 start.fY);
2666 r.fTop = offset;
2667 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002668 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002669 }
2670 }
2671}
2672
reed@google.come0d9ce82014-04-23 04:00:17 +00002673void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2674 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002675 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002676
2677 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002678 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002679 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002680 DrawTextDecorations(iter, dfp.paint(),
2681 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002682 }
2683
reed@google.com4e2b3d32011-04-07 14:18:59 +00002684 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002685}
2686
reed@google.come0d9ce82014-04-23 04:00:17 +00002687void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2688 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002689 SkPoint textOffset = SkPoint::Make(0, 0);
2690
halcanary96fcdcc2015-08-27 07:41:13 -07002691 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002692
reed@android.com8a1c16f2008-12-17 15:59:43 +00002693 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002694 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002695 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002696 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002698
reed@google.com4e2b3d32011-04-07 14:18:59 +00002699 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002700}
2701
reed@google.come0d9ce82014-04-23 04:00:17 +00002702void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2703 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002704
2705 SkPoint textOffset = SkPoint::Make(0, constY);
2706
halcanary96fcdcc2015-08-27 07:41:13 -07002707 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002708
reed@android.com8a1c16f2008-12-17 15:59:43 +00002709 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002710 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002711 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002712 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002713 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002714
reed@google.com4e2b3d32011-04-07 14:18:59 +00002715 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002716}
2717
reed@google.come0d9ce82014-04-23 04:00:17 +00002718void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2719 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002720 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002721
reed@android.com8a1c16f2008-12-17 15:59:43 +00002722 while (iter.next()) {
2723 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002724 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002725 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002726
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002727 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002728}
2729
reed45561a02016-07-07 12:47:17 -07002730void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2731 const SkRect* cullRect, const SkPaint& paint) {
2732 if (cullRect && this->quickReject(*cullRect)) {
2733 return;
2734 }
2735
2736 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2737
2738 while (iter.next()) {
2739 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2740 }
2741
2742 LOOPER_END
2743}
2744
fmalita00d5c2c2014-08-21 08:53:26 -07002745void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2746 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002747
fmalita85d5eb92015-03-04 11:20:12 -08002748 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002749 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002750 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002751 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002752 SkRect tmp;
2753 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2754 return;
2755 }
2756 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002757 }
2758
fmalita024f9962015-03-03 19:08:17 -08002759 // We cannot filter in the looper as we normally do, because the paint is
2760 // incomplete at this point (text-related attributes are embedded within blob run paints).
2761 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002762 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002763
fmalita85d5eb92015-03-04 11:20:12 -08002764 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002765
fmalitaaa1b9122014-08-28 14:32:24 -07002766 while (iter.next()) {
2767 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002768 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002769 }
2770
fmalitaaa1b9122014-08-28 14:32:24 -07002771 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002772
2773 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002774}
2775
reed@google.come0d9ce82014-04-23 04:00:17 +00002776// These will become non-virtual, so they always call the (virtual) onDraw... method
2777void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2778 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002779 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002780 if (byteLength) {
2781 this->onDrawText(text, byteLength, x, y, paint);
2782 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002783}
2784void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2785 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002786 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002787 if (byteLength) {
2788 this->onDrawPosText(text, byteLength, pos, paint);
2789 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002790}
2791void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2792 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002793 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002794 if (byteLength) {
2795 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2796 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002797}
2798void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2799 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002800 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002801 if (byteLength) {
2802 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2803 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002804}
reed45561a02016-07-07 12:47:17 -07002805void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2806 const SkRect* cullRect, const SkPaint& paint) {
2807 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2808 if (byteLength) {
2809 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2810 }
2811}
fmalita00d5c2c2014-08-21 08:53:26 -07002812void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2813 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002814 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002815 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002816 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002817}
reed@google.come0d9ce82014-04-23 04:00:17 +00002818
reed41af9662015-01-05 07:49:08 -08002819void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2820 const SkPoint verts[], const SkPoint texs[],
Mike Reedfaba3712016-11-03 14:45:31 -04002821 const SkColor colors[], SkBlendMode bmode,
reed41af9662015-01-05 07:49:08 -08002822 const uint16_t indices[], int indexCount,
2823 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002824 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002825 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002826
reed@android.com8a1c16f2008-12-17 15:59:43 +00002827 while (iter.next()) {
2828 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
Mike Reedfaba3712016-11-03 14:45:31 -04002829 colors, bmode, indices, indexCount,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002830 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002831 }
reed@google.com4b226022011-01-11 18:32:13 +00002832
reed@google.com4e2b3d32011-04-07 14:18:59 +00002833 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002834}
2835
dandovb3c9d1c2014-08-12 08:34:29 -07002836void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reed7d954ad2016-10-28 15:42:34 -04002837 const SkPoint texCoords[4], SkBlendMode bmode,
2838 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002839 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002840 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002841 return;
2842 }
mtklein6cfa73a2014-08-13 13:33:49 -07002843
Mike Reedfaba3712016-11-03 14:45:31 -04002844 this->onDrawPatch(cubics, colors, texCoords, bmode, paint);
msarett9340c262016-09-22 05:20:21 -07002845}
2846
2847void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedfaba3712016-11-03 14:45:31 -04002848 const SkPoint texCoords[4], SkBlendMode bmode,
Mike Reed7d954ad2016-10-28 15:42:34 -04002849 const SkPaint& paint) {
dandovecfff212014-08-04 10:02:00 -07002850 // Since a patch is always within the convex hull of the control points, we discard it when its
2851 // bounding rectangle is completely outside the current clip.
2852 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002853 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002854 if (this->quickReject(bounds)) {
2855 return;
2856 }
mtklein6cfa73a2014-08-13 13:33:49 -07002857
halcanary96fcdcc2015-08-27 07:41:13 -07002858 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002859
dandovecfff212014-08-04 10:02:00 -07002860 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002861 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, bmode, paint);
dandovecfff212014-08-04 10:02:00 -07002862 }
mtklein6cfa73a2014-08-13 13:33:49 -07002863
dandovecfff212014-08-04 10:02:00 -07002864 LOOPER_END
2865}
2866
reeda8db7282015-07-07 10:22:31 -07002867void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002868 RETURN_ON_NULL(dr);
2869 if (x || y) {
2870 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2871 this->onDrawDrawable(dr, &matrix);
2872 } else {
2873 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002874 }
2875}
2876
reeda8db7282015-07-07 10:22:31 -07002877void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002878 RETURN_ON_NULL(dr);
2879 if (matrix && matrix->isIdentity()) {
2880 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002881 }
reede3b38ce2016-01-08 09:18:44 -08002882 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002883}
2884
2885void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reed2a62e852016-10-03 10:35:37 -07002886 // drawable bounds are no longer reliable (e.g. android displaylist)
2887 // so don't use them for quick-reject
reeda8db7282015-07-07 10:22:31 -07002888 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002889}
2890
reed71c3c762015-06-24 10:29:17 -07002891void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
Mike Reedfaba3712016-11-03 14:45:31 -04002892 const SkColor colors[], int count, SkBlendMode bmode,
reed71c3c762015-06-24 10:29:17 -07002893 const SkRect* cull, const SkPaint* paint) {
2894 if (cull && this->quickReject(*cull)) {
2895 return;
2896 }
2897
2898 SkPaint pnt;
2899 if (paint) {
2900 pnt = *paint;
2901 }
halcanary9d524f22016-03-29 09:03:52 -07002902
halcanary96fcdcc2015-08-27 07:41:13 -07002903 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002904 while (iter.next()) {
Mike Reedfaba3712016-11-03 14:45:31 -04002905 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, bmode, pnt);
reed71c3c762015-06-24 10:29:17 -07002906 }
2907 LOOPER_END
2908}
2909
reedf70b5312016-03-04 16:36:20 -08002910void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2911 SkASSERT(key);
2912
2913 SkPaint paint;
2914 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2915 while (iter.next()) {
2916 iter.fDevice->drawAnnotation(iter, rect, key, value);
2917 }
2918 LOOPER_END
2919}
2920
reed@android.com8a1c16f2008-12-17 15:59:43 +00002921//////////////////////////////////////////////////////////////////////////////
2922// These methods are NOT virtual, and therefore must call back into virtual
2923// methods, rather than actually drawing themselves.
2924//////////////////////////////////////////////////////////////////////////////
2925
reed374772b2016-10-05 17:33:02 -07002926void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002927 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002928 SkPaint paint;
2929
2930 paint.setARGB(a, r, g, b);
reed374772b2016-10-05 17:33:02 -07002931 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002932 this->drawPaint(paint);
2933}
2934
reed374772b2016-10-05 17:33:02 -07002935void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
danakj9881d632014-11-26 12:41:06 -08002936 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002937 SkPaint paint;
2938
2939 paint.setColor(c);
reed374772b2016-10-05 17:33:02 -07002940 paint.setBlendMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002941 this->drawPaint(paint);
2942}
2943
2944void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002945 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002946 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002947
reed@android.com8a1c16f2008-12-17 15:59:43 +00002948 pt.set(x, y);
2949 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2950}
2951
2952void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002953 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002954 SkPoint pt;
2955 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002956
reed@android.com8a1c16f2008-12-17 15:59:43 +00002957 pt.set(x, y);
2958 paint.setColor(color);
2959 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2960}
2961
2962void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2963 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002964 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002965 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002966
reed@android.com8a1c16f2008-12-17 15:59:43 +00002967 pts[0].set(x0, y0);
2968 pts[1].set(x1, y1);
2969 this->drawPoints(kLines_PointMode, 2, pts, paint);
2970}
2971
2972void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2973 SkScalar right, SkScalar bottom,
2974 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002975 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002976 SkRect r;
2977
2978 r.set(left, top, right, bottom);
2979 this->drawRect(r, paint);
2980}
2981
2982void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2983 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002984 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002985 if (radius < 0) {
2986 radius = 0;
2987 }
2988
2989 SkRect r;
2990 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002991 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002992}
2993
2994void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2995 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002996 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002997 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002998 SkRRect rrect;
2999 rrect.setRectXY(r, rx, ry);
3000 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003001 } else {
3002 this->drawRect(r, paint);
3003 }
3004}
3005
reed@android.com8a1c16f2008-12-17 15:59:43 +00003006void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3007 SkScalar sweepAngle, bool useCenter,
3008 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003009 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003010 if (oval.isEmpty() || !sweepAngle) {
3011 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003012 }
bsalomon21af9ca2016-08-25 12:29:23 -07003013 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003014}
3015
3016void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3017 const SkPath& path, SkScalar hOffset,
3018 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003019 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003020 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003021
reed@android.com8a1c16f2008-12-17 15:59:43 +00003022 matrix.setTranslate(hOffset, vOffset);
3023 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3024}
3025
reed@android.comf76bacf2009-05-13 14:00:33 +00003026///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003027
3028/**
3029 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3030 * against the playback cost of recursing into the subpicture to get at its actual ops.
3031 *
3032 * For now we pick a conservatively small value, though measurement (and other heuristics like
3033 * the type of ops contained) may justify changing this value.
3034 */
3035#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003036
reedd5fa1a42014-08-09 11:08:05 -07003037void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003038 RETURN_ON_NULL(picture);
3039
reed1c2c4412015-04-30 13:09:24 -07003040 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003041 if (matrix && matrix->isIdentity()) {
3042 matrix = nullptr;
3043 }
3044 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3045 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3046 picture->playback(this);
3047 } else {
3048 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003049 }
3050}
robertphillips9b14f262014-06-04 05:40:44 -07003051
reedd5fa1a42014-08-09 11:08:05 -07003052void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3053 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003054 if (!paint || paint->canComputeFastBounds()) {
3055 SkRect bounds = picture->cullRect();
3056 if (paint) {
3057 paint->computeFastBounds(bounds, &bounds);
3058 }
3059 if (matrix) {
3060 matrix->mapRect(&bounds);
3061 }
3062 if (this->quickReject(bounds)) {
3063 return;
3064 }
3065 }
3066
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003067 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003068 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003069}
3070
vjiaoblack95302da2016-07-21 10:25:54 -07003071#ifdef SK_EXPERIMENTAL_SHADOWING
3072void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3073 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003074 const SkPaint* paint,
3075 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003076 RETURN_ON_NULL(picture);
3077
3078 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3079
vjiaoblacke6f5d562016-08-25 06:30:23 -07003080 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003081}
3082
3083void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3084 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003085 const SkPaint* paint,
3086 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003087 if (!paint || paint->canComputeFastBounds()) {
3088 SkRect bounds = picture->cullRect();
3089 if (paint) {
3090 paint->computeFastBounds(bounds, &bounds);
3091 }
3092 if (matrix) {
3093 matrix->mapRect(&bounds);
3094 }
3095 if (this->quickReject(bounds)) {
3096 return;
3097 }
3098 }
3099
3100 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3101
vjiaoblacke6f5d562016-08-25 06:30:23 -07003102 sk_sp<SkImage> povDepthMap;
3103 sk_sp<SkImage> diffuseMap;
3104
vjiaoblack904527d2016-08-09 09:32:09 -07003105 // povDepthMap
3106 {
3107 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003108 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3109 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003110 sk_sp<SkLights> povLight = builder.finish();
3111
3112 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3113 picture->cullRect().height(),
3114 kBGRA_8888_SkColorType,
3115 kOpaque_SkAlphaType);
3116
3117 // Create a new surface (that matches the backend of canvas)
3118 // to create the povDepthMap
3119 sk_sp<SkSurface> surf(this->makeSurface(info));
3120
3121 // Wrap another SPFCanvas around the surface
3122 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3123 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3124
3125 // set the depth map canvas to have the light as the user's POV
3126 depthMapCanvas->setLights(std::move(povLight));
3127
3128 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003129 povDepthMap = surf->makeImageSnapshot();
3130 }
3131
3132 // diffuseMap
3133 {
3134 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3135 picture->cullRect().height(),
3136 kBGRA_8888_SkColorType,
3137 kOpaque_SkAlphaType);
3138
3139 sk_sp<SkSurface> surf(this->makeSurface(info));
3140 surf->getCanvas()->drawPicture(picture);
3141
3142 diffuseMap = surf->makeImageSnapshot();
3143 }
vjiaoblack904527d2016-08-09 09:32:09 -07003144
3145 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3146 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003147 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3148 SkShader::kClamp_TileMode);
vjiaoblackb2796fd2016-09-09 09:22:39 -07003149
3150 // TODO: pass the depth to the shader in vertices, or uniforms
3151 // so we don't have to render depth and color separately
3152 for (int i = 0; i < fLights->numLights(); ++i) {
3153 // skip over ambient lights; they don't cast shadows
3154 // lights that have shadow maps do not need updating (because lights are immutable)
3155 sk_sp<SkImage> depthMap;
3156 SkISize shMapSize;
3157
3158 if (fLights->light(i).getShadowMap() != nullptr) {
3159 continue;
3160 }
3161
3162 if (fLights->light(i).isRadial()) {
3163 shMapSize.fHeight = 1;
3164 shMapSize.fWidth = (int) picture->cullRect().width();
3165
3166 SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1,
3167 kBGRA_8888_SkColorType,
3168 kOpaque_SkAlphaType);
3169
3170 // Create new surface (that matches the backend of canvas)
3171 // for each shadow map
3172 sk_sp<SkSurface> surf(this->makeSurface(info));
3173
3174 // Wrap another SPFCanvas around the surface
3175 SkCanvas* depthMapCanvas = surf->getCanvas();
3176
3177 SkLights::Builder builder;
3178 builder.add(fLights->light(i));
3179 sk_sp<SkLights> curLight = builder.finish();
3180
3181 sk_sp<SkShader> shadowMapShader;
3182 shadowMapShader = SkRadialShadowMapShader::Make(
3183 povDepthShader, curLight,
3184 (int) picture->cullRect().width(),
3185 (int) picture->cullRect().height());
3186
3187 SkPaint shadowMapPaint;
3188 shadowMapPaint.setShader(std::move(shadowMapShader));
3189
3190 depthMapCanvas->setLights(curLight);
3191
3192 depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(),
3193 diffuseMap->height()),
3194 shadowMapPaint);
3195
3196 depthMap = surf->makeImageSnapshot();
3197
3198 } else {
3199 // TODO: compute the correct size of the depth map from the light properties
3200 // TODO: maybe add a kDepth_8_SkColorType
3201 // TODO: find actual max depth of picture
3202 shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3203 fLights->light(i), 255,
3204 (int) picture->cullRect().width(),
3205 (int) picture->cullRect().height());
3206
3207 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3208 kBGRA_8888_SkColorType,
3209 kOpaque_SkAlphaType);
3210
3211 // Create a new surface (that matches the backend of canvas)
3212 // for each shadow map
3213 sk_sp<SkSurface> surf(this->makeSurface(info));
3214
3215 // Wrap another SPFCanvas around the surface
3216 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3217 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3218 depthMapCanvas->setShadowParams(params);
3219
3220 // set the depth map canvas to have the light we're drawing.
3221 SkLights::Builder builder;
3222 builder.add(fLights->light(i));
3223 sk_sp<SkLights> curLight = builder.finish();
3224 depthMapCanvas->setLights(std::move(curLight));
3225
3226 depthMapCanvas->drawPicture(picture);
3227 depthMap = surf->makeImageSnapshot();
3228 }
3229
3230 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3231 fLights->light(i).setShadowMap(std::move(depthMap));
3232 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3233 // we blur the variance map
3234 SkPaint blurPaint;
3235 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3236 params.fShadowRadius, nullptr));
3237
3238 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3239 kBGRA_8888_SkColorType,
3240 kOpaque_SkAlphaType);
3241
3242 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3243
3244 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3245
3246 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3247 }
3248 }
3249
3250 SkPaint shadowPaint;
vjiaoblack904527d2016-08-09 09:32:09 -07003251 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3252 std::move(diffuseShader),
vjiaoblackb2796fd2016-09-09 09:22:39 -07003253 fLights,
vjiaoblack904527d2016-08-09 09:32:09 -07003254 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003255 diffuseMap->height(),
3256 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003257
3258 shadowPaint.setShader(shadowShader);
3259
3260 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003261}
3262#endif
3263
reed@android.com8a1c16f2008-12-17 15:59:43 +00003264///////////////////////////////////////////////////////////////////////////////
3265///////////////////////////////////////////////////////////////////////////////
3266
reed3aafe112016-08-18 12:45:34 -07003267SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003268 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003269
3270 SkASSERT(canvas);
3271
reed3aafe112016-08-18 12:45:34 -07003272 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003273 fDone = !fImpl->next();
3274}
3275
3276SkCanvas::LayerIter::~LayerIter() {
3277 fImpl->~SkDrawIter();
3278}
3279
3280void SkCanvas::LayerIter::next() {
3281 fDone = !fImpl->next();
3282}
3283
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003284SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003285 return fImpl->getDevice();
3286}
3287
3288const SkMatrix& SkCanvas::LayerIter::matrix() const {
3289 return fImpl->getMatrix();
3290}
3291
3292const SkPaint& SkCanvas::LayerIter::paint() const {
3293 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003294 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003295 paint = &fDefaultPaint;
3296 }
3297 return *paint;
3298}
3299
reed1e7f5e72016-04-27 07:49:17 -07003300const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003301int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3302int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003303
3304///////////////////////////////////////////////////////////////////////////////
3305
fmalitac3b589a2014-06-05 12:40:07 -07003306SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003307
3308///////////////////////////////////////////////////////////////////////////////
3309
3310static bool supported_for_raster_canvas(const SkImageInfo& info) {
3311 switch (info.alphaType()) {
3312 case kPremul_SkAlphaType:
3313 case kOpaque_SkAlphaType:
3314 break;
3315 default:
3316 return false;
3317 }
3318
3319 switch (info.colorType()) {
3320 case kAlpha_8_SkColorType:
3321 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003322 case kN32_SkColorType:
junov9e3dbdf2016-10-13 13:14:27 -07003323 case kRGBA_F16_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003324 break;
3325 default:
3326 return false;
3327 }
3328
3329 return true;
3330}
3331
Mike Reed5df49342016-11-12 08:06:55 -06003332std::unique_ptr<SkCanvas> SkCanvas::MakeRasterDirect(const SkImageInfo& info, void* pixels,
3333 size_t rowBytes) {
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003334 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003335 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003336 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003337
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003338 SkBitmap bitmap;
3339 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003340 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003341 }
Mike Reed5df49342016-11-12 08:06:55 -06003342 return skstd::make_unique<SkCanvas>(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003343}
reedd5fa1a42014-08-09 11:08:05 -07003344
3345///////////////////////////////////////////////////////////////////////////////
3346
3347SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003348 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003349 : fCanvas(canvas)
3350 , fSaveCount(canvas->getSaveCount())
3351{
bsalomon49f085d2014-09-05 13:34:00 -07003352 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003353 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003354 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003355 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003356 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003357 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003358 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003359 canvas->save();
3360 }
mtklein6cfa73a2014-08-13 13:33:49 -07003361
bsalomon49f085d2014-09-05 13:34:00 -07003362 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003363 canvas->concat(*matrix);
3364 }
3365}
3366
3367SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3368 fCanvas->restoreToCount(fSaveCount);
3369}
reede8f30622016-03-23 18:59:25 -07003370
Florin Malitaee424ac2016-12-01 12:47:59 -05003371///////////////////////////////////////////////////////////////////////////////
3372
3373SkNoDrawCanvas::SkNoDrawCanvas(int width, int height)
3374 : INHERITED(SkIRect::MakeWH(width, height), kConservativeRasterClip_InitFlag) {}
3375
Florin Malita439ace92016-12-02 12:05:41 -05003376SkNoDrawCanvas::SkNoDrawCanvas(const SkIRect& bounds)
3377 : INHERITED(bounds, kConservativeRasterClip_InitFlag) {}
3378
Florin Malitaee424ac2016-12-01 12:47:59 -05003379SkCanvas::SaveLayerStrategy SkNoDrawCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
3380 (void)this->INHERITED::getSaveLayerStrategy(rec);
3381 return kNoLayer_SaveLayerStrategy;
3382}
3383
3384///////////////////////////////////////////////////////////////////////////////
reed73603f32016-09-20 08:42:38 -07003385
3386const SkCanvas::ClipOp SkCanvas::kDifference_Op;
3387const SkCanvas::ClipOp SkCanvas::kIntersect_Op;
3388const SkCanvas::ClipOp SkCanvas::kUnion_Op;
3389const SkCanvas::ClipOp SkCanvas::kXOR_Op;
3390const SkCanvas::ClipOp SkCanvas::kReverseDifference_Op;
3391const SkCanvas::ClipOp SkCanvas::kReplace_Op;
3392
3393static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, "");
3394static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, "");
3395static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, "");
3396static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, "");
3397static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, "");
3398static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, "");