blob: fc1897526cde8679dab48cd323db81362c829fda [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
bungemand3ebb482015-08-05 13:57:49 -07008#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -070010#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkClipStack.h"
reeddbc3cef2015-04-29 12:18:57 -070012#include "SkColorFilter.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080017#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080019#include "SkImage_Base.h"
senorblanco900c3672016-04-27 11:31:23 -070020#include "SkImageFilter.h"
21#include "SkImageFilterCache.h"
msarettc573a402016-08-02 08:05:56 -070022#include "SkLatticeIter.h"
reed262a71b2015-12-05 13:07:27 -080023#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000024#include "SkMetaData.h"
msarettfbfa2582016-08-12 08:29:08 -070025#include "SkNx.h"
reedc83a2972015-07-16 07:40:45 -070026#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070027#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000028#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000029#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080030#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000031#include "SkRRect.h"
vjiaoblack904527d2016-08-09 09:32:09 -070032#include "SkShadowPaintFilterCanvas.h"
33#include "SkShadowShader.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000034#include "SkSmallAllocator.h"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
reed@google.com97af1a62012-08-28 12:19:02 +000036#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070037#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000038#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000039#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080040#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070041#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000042
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000043#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080044#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000045#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070046#include "SkGrPriv.h"
vjiaoblacke6f5d562016-08-25 06:30:23 -070047
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#endif
49
reede3b38ce2016-01-08 09:18:44 -080050#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
51
reed2d1afab2016-06-29 14:33:11 -070052//#define SK_SUPPORT_PRECHECK_CLIPRECT
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...
125//#define SK_ENABLE_CLIP_QUICKREJECT
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126//#define SK_TRACE_SAVERESTORE
127
128#ifdef SK_TRACE_SAVERESTORE
129 static int gLayerCounter;
130 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
131 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
132
133 static int gRecCounter;
134 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
135 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
136
137 static int gCanvasCounter;
138 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
139 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
140#else
141 #define inc_layer()
142 #define dec_layer()
143 #define inc_rec()
144 #define dec_rec()
145 #define inc_canvas()
146 #define dec_canvas()
147#endif
148
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000149typedef SkTLazy<SkPaint> SkLazyPaint;
150
reedc83a2972015-07-16 07:40:45 -0700151void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000152 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700153 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
154 ? SkSurface::kDiscard_ContentChangeMode
155 : SkSurface::kRetain_ContentChangeMode);
156 }
157}
158
159void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
160 ShaderOverrideOpacity overrideOpacity) {
161 if (fSurfaceBase) {
162 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
163 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
164 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
165 // and therefore we don't care which mode we're in.
166 //
167 if (fSurfaceBase->outstandingImageSnapshot()) {
168 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
169 mode = SkSurface::kDiscard_ContentChangeMode;
170 }
171 }
172 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000173 }
174}
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000178/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 The clip/matrix/proc are fields that reflect the top of the save/restore
180 stack. Whenever the canvas changes, it marks a dirty flag, and then before
181 these are used (assuming we're not on a layer) we rebuild these cache
182 values: they reflect the top of the save stack, but translated and clipped
183 by the device's XY offset and bitmap-bounds.
184*/
185struct DeviceCM {
186 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000187 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000188 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000189 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700190 const SkMatrix* fMatrix;
191 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700192 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193
reed96e657d2015-03-10 17:30:07 -0700194 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700195 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700196 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700197 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700198 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700199 {
reed2c9e2002016-07-25 08:05:22 -0700200 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000201 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700202 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000203 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000205 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700206 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700207 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000208 }
reed@google.com4b226022011-01-11 18:32:13 +0000209
mtkleinfeaadee2015-04-08 11:25:48 -0700210 void reset(const SkIRect& bounds) {
211 SkASSERT(!fPaint);
212 SkASSERT(!fNext);
213 SkASSERT(fDevice);
214 fClip.setRect(bounds);
215 }
216
reed@google.com045e62d2011-10-24 12:19:46 +0000217 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
218 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000219 int x = fDevice->getOrigin().x();
220 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 int width = fDevice->width();
222 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000223
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 if ((x | y) == 0) {
225 fMatrix = &totalMatrix;
226 fClip = totalClip;
227 } else {
228 fMatrixStorage = totalMatrix;
229 fMatrixStorage.postTranslate(SkIntToScalar(-x),
230 SkIntToScalar(-y));
231 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000232
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 totalClip.translate(-x, -y, &fClip);
234 }
235
reed@google.com045e62d2011-10-24 12:19:46 +0000236 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
238 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000239
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000241 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 SkRegion::kDifference_Op);
243 }
reed@google.com4b226022011-01-11 18:32:13 +0000244
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000245 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
246
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247#ifdef SK_DEBUG
248 if (!fClip.isEmpty()) {
249 SkIRect deviceR;
250 deviceR.set(0, 0, width, height);
251 SkASSERT(deviceR.contains(fClip.getBounds()));
252 }
253#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000254 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255};
256
257/* This is the record we keep for each save/restore level in the stack.
258 Since a level optionally copies the matrix and/or stack, we have pointers
259 for these fields. If the value is copied for this level, the copy is
260 stored in the ...Storage field, and the pointer points to that. If the
261 value is not copied for this level, we ignore ...Storage, and just point
262 at the corresponding value in the previous level in the stack.
263*/
264class SkCanvas::MCRec {
265public:
reed1f836ee2014-07-07 07:49:34 -0700266 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700267 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 /* If there are any layers in the stack, this points to the top-most
269 one that is at or below this level in the stack (so we know what
270 bitmap/device to draw into from this level. This value is NOT
271 reference counted, since the real owner is either our fLayer field,
272 or a previous one in a lower level.)
273 */
reed2ff1fce2014-12-11 07:07:37 -0800274 DeviceCM* fTopLayer;
275 SkRasterClip fRasterClip;
276 SkMatrix fMatrix;
277 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278
vjiaoblacke5de1302016-07-13 14:05:28 -0700279 // This is the current cumulative depth (aggregate of all done translateZ calls)
280 SkScalar fCurDrawDepth;
281
reedd9544982014-09-09 18:46:22 -0700282 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700283 fFilter = nullptr;
284 fLayer = nullptr;
285 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800286 fMatrix.reset();
287 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700288 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700289
reedd9544982014-09-09 18:46:22 -0700290 // don't bother initializing fNext
291 inc_rec();
292 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700293 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
294 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700295 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700296 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700297 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800298 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700299
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300 // don't bother initializing fNext
301 inc_rec();
302 }
303 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000304 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700305 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306 dec_rec();
307 }
mtkleinfeaadee2015-04-08 11:25:48 -0700308
309 void reset(const SkIRect& bounds) {
310 SkASSERT(fLayer);
311 SkASSERT(fDeferredSaveCount == 0);
312
313 fMatrix.reset();
314 fRasterClip.setRect(bounds);
315 fLayer->reset(bounds);
316 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000317};
318
319class SkDrawIter : public SkDraw {
320public:
reed3aafe112016-08-18 12:45:34 -0700321 SkDrawIter(SkCanvas* canvas) {
junov@google.com4370aed2012-01-18 16:21:08 +0000322 canvas = canvas->canvasForDrawIter();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323 canvas->updateDeviceCMCache();
324
reed687fa1c2015-04-07 08:00:56 -0700325 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000326 fCurrLayer = canvas->fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 }
reed@google.com4b226022011-01-11 18:32:13 +0000328
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 bool next() {
330 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700331 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
332 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333 }
334
reed@google.comf68c5e22012-02-24 16:38:58 +0000335 const DeviceCM* rec = fCurrLayer;
336 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337
338 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000339 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700341 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700342 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700343 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000345 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346
347 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700348 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000349
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 return true;
351 }
352 return false;
353 }
reed@google.com4b226022011-01-11 18:32:13 +0000354
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000355 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700356 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000357 int getX() const { return fDevice->getOrigin().x(); }
358 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000361
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363 const DeviceCM* fCurrLayer;
364 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365
366 typedef SkDraw INHERITED;
367};
368
369/////////////////////////////////////////////////////////////////////////////
370
reeddbc3cef2015-04-29 12:18:57 -0700371static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
372 return lazy->isValid() ? lazy->get() : lazy->set(orig);
373}
374
375/**
376 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700377 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700378 */
reedd053ce92016-03-22 10:17:23 -0700379static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700380 SkImageFilter* imgf = paint.getImageFilter();
381 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700382 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700383 }
384
reedd053ce92016-03-22 10:17:23 -0700385 SkColorFilter* imgCFPtr;
386 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700387 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700388 }
reedd053ce92016-03-22 10:17:23 -0700389 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700390
391 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700392 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700393 // there is no existing paint colorfilter, so we can just return the imagefilter's
394 return imgCF;
395 }
396
397 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
398 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700399 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700400}
401
senorblanco87e066e2015-10-28 11:23:36 -0700402/**
403 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
404 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
405 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
406 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
407 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
408 * conservative "effective" bounds based on the settings in the paint... with one exception. This
409 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
410 * deliberately ignored.
411 */
412static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
413 const SkRect& rawBounds,
414 SkRect* storage) {
415 SkPaint tmpUnfiltered(paint);
416 tmpUnfiltered.setImageFilter(nullptr);
417 if (tmpUnfiltered.canComputeFastBounds()) {
418 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
419 } else {
420 return rawBounds;
421 }
422}
423
reed@android.com8a1c16f2008-12-17 15:59:43 +0000424class AutoDrawLooper {
425public:
senorblanco87e066e2015-10-28 11:23:36 -0700426 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
427 // paint. It's used to determine the size of the offscreen layer for filters.
428 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700429 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700430 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000431 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800432#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800434#else
435 fFilter = nullptr;
436#endif
reed4a8126e2014-09-22 07:29:03 -0700437 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000438 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700439 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000440 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441
reedd053ce92016-03-22 10:17:23 -0700442 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700443 if (simplifiedCF) {
444 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700445 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700446 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700447 fPaint = paint;
448 }
449
450 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700451 /**
452 * We implement ImageFilters for a given draw by creating a layer, then applying the
453 * imagefilter to the pixels of that layer (its backing surface/image), and then
454 * we call restore() to xfer that layer to the main canvas.
455 *
456 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
457 * 2. Generate the src pixels:
458 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
459 * return (fPaint). We then draw the primitive (using srcover) into a cleared
460 * buffer/surface.
461 * 3. Restore the layer created in #1
462 * The imagefilter is passed the buffer/surface from the layer (now filled with the
463 * src pixels of the primitive). It returns a new "filtered" buffer, which we
464 * draw onto the previous layer using the xfermode from the original paint.
465 */
reed@google.com8926b162012-03-23 15:36:36 +0000466 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700467 tmp.setImageFilter(fPaint->getImageFilter());
reedcfb6bdf2016-03-29 11:32:50 -0700468 tmp.setXfermode(sk_ref_sp(fPaint->getXfermode()));
senorblanco87e066e2015-10-28 11:23:36 -0700469 SkRect storage;
470 if (rawBounds) {
471 // Make rawBounds include all paint outsets except for those due to image filters.
472 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
473 }
reedbfd5f172016-01-07 11:28:08 -0800474 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700475 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700476 fTempLayerForImageFilter = true;
477 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000478 }
479
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000480 if (SkDrawLooper* looper = paint.getLooper()) {
481 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
482 looper->contextSize());
483 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000484 fIsSimple = false;
485 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700486 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000487 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700488 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000489 }
490 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000491
reed@android.com8a1c16f2008-12-17 15:59:43 +0000492 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700493 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000494 fCanvas->internalRestore();
495 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000496 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000498
reed@google.com4e2b3d32011-04-07 14:18:59 +0000499 const SkPaint& paint() const {
500 SkASSERT(fPaint);
501 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000502 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000503
reed@google.com129ec222012-05-15 13:24:09 +0000504 bool next(SkDrawFilter::Type drawType) {
505 if (fDone) {
506 return false;
507 } else if (fIsSimple) {
508 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000509 return !fPaint->nothingToDraw();
510 } else {
511 return this->doNext(drawType);
512 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000513 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000514
reed@android.com8a1c16f2008-12-17 15:59:43 +0000515private:
reeddbc3cef2015-04-29 12:18:57 -0700516 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
517 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000518 SkCanvas* fCanvas;
519 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000520 SkDrawFilter* fFilter;
521 const SkPaint* fPaint;
522 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700523 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000524 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000525 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000526 SkDrawLooper::Context* fLooperContext;
527 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000528
529 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530};
531
reed@google.com129ec222012-05-15 13:24:09 +0000532bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700533 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000534 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700535 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000536
reeddbc3cef2015-04-29 12:18:57 -0700537 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
538 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000539
reed5c476fb2015-04-20 08:04:21 -0700540 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700541 paint->setImageFilter(nullptr);
542 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000543 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000544
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000545 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000546 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000547 return false;
548 }
549 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000550 if (!fFilter->filter(paint, drawType)) {
551 fDone = true;
552 return false;
553 }
halcanary96fcdcc2015-08-27 07:41:13 -0700554 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000555 // no looper means we only draw once
556 fDone = true;
557 }
558 }
559 fPaint = paint;
560
561 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000562 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000563 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000564 }
565
566 // call this after any possible paint modifiers
567 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700568 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000569 return false;
570 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000571 return true;
572}
573
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574////////// macros to place around the internal draw calls //////////////////
575
reed3aafe112016-08-18 12:45:34 -0700576#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
577 this->predrawNotify(); \
578 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
579 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800580 SkDrawIter iter(this);
581
582
reed@google.com8926b162012-03-23 15:36:36 +0000583#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000584 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700585 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000586 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000587 SkDrawIter iter(this);
588
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000589#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000590 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700591 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000592 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000594
reedc83a2972015-07-16 07:40:45 -0700595#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
596 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700597 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700598 while (looper.next(type)) { \
599 SkDrawIter iter(this);
600
reed@google.com4e2b3d32011-04-07 14:18:59 +0000601#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000602
603////////////////////////////////////////////////////////////////////////////
604
msarettfbfa2582016-08-12 08:29:08 -0700605static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
606 if (bounds.isEmpty()) {
607 return SkRect::MakeEmpty();
608 }
609
610 // Expand bounds out by 1 in case we are anti-aliasing. We store the
611 // bounds as floats to enable a faster quick reject implementation.
612 SkRect dst;
613 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
614 return dst;
615}
616
mtkleinfeaadee2015-04-08 11:25:48 -0700617void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
618 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700619 fClipStack->reset();
620 fMCRec->reset(bounds);
621
622 // We're peering through a lot of structs here. Only at this scope do we
623 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
624 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700625 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700626 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700627}
628
reedd9544982014-09-09 18:46:22 -0700629SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800630 if (device && device->forceConservativeRasterClip()) {
631 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
632 }
633 // Since init() is only called once by our constructors, it is safe to perform this
634 // const-cast.
635 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
636
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000637 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000638 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700639 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800640 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700641 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700642#ifdef SK_EXPERIMENTAL_SHADOWING
643 fLights = nullptr;
644#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000645
halcanary385fe4d2015-08-26 13:07:48 -0700646 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700647
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700649 new (fMCRec) MCRec(fConservativeRasterClip);
msarett9637ea92016-08-18 14:03:30 -0700650 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000651
reeda499f902015-05-01 09:34:31 -0700652 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
653 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700654 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700655 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700656
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658
halcanary96fcdcc2015-08-27 07:41:13 -0700659 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000660
reedf92c8662014-08-18 08:02:43 -0700661 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700662 // The root device and the canvas should always have the same pixel geometry
663 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700664 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800665 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700666 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700667 }
msarettfbfa2582016-08-12 08:29:08 -0700668
reedf92c8662014-08-18 08:02:43 -0700669 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670}
671
reed@google.comcde92112011-07-06 20:00:52 +0000672SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000673 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700674 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800675 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000676{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000677 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000678
halcanary96fcdcc2015-08-27 07:41:13 -0700679 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000680}
681
reedd9544982014-09-09 18:46:22 -0700682static SkBitmap make_nopixels(int width, int height) {
683 SkBitmap bitmap;
684 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
685 return bitmap;
686}
687
688class SkNoPixelsBitmapDevice : public SkBitmapDevice {
689public:
robertphillipsfcf78292015-06-19 11:49:52 -0700690 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
691 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800692 {
693 this->setOrigin(bounds.x(), bounds.y());
694 }
reedd9544982014-09-09 18:46:22 -0700695
696private:
piotaixrb5fae932014-09-24 13:03:30 -0700697
reedd9544982014-09-09 18:46:22 -0700698 typedef SkBitmapDevice INHERITED;
699};
700
reed96a857e2015-01-25 10:33:58 -0800701SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000702 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800703 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800704 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000705{
706 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700707
halcanary385fe4d2015-08-26 13:07:48 -0700708 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
709 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700710}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000711
reed78e27682014-11-19 08:04:34 -0800712SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700713 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700714 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800715 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700716{
717 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700718
halcanary385fe4d2015-08-26 13:07:48 -0700719 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700720}
721
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000722SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000723 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700724 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800725 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000726{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000727 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700728
reedd9544982014-09-09 18:46:22 -0700729 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000730}
731
robertphillipsfcf78292015-06-19 11:49:52 -0700732SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
733 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700734 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800735 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700736{
737 inc_canvas();
738
739 this->init(device, flags);
740}
741
reed4a8126e2014-09-22 07:29:03 -0700742SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700743 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700744 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800745 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700746{
747 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700748
halcanary385fe4d2015-08-26 13:07:48 -0700749 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700750 this->init(device, kDefault_InitFlags);
751}
reed29c857d2014-09-21 10:25:07 -0700752
reed4a8126e2014-09-22 07:29:03 -0700753SkCanvas::SkCanvas(const SkBitmap& bitmap)
754 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
755 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800756 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700757{
758 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700759
halcanary385fe4d2015-08-26 13:07:48 -0700760 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700761 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000762}
763
764SkCanvas::~SkCanvas() {
765 // free up the contents of our deque
766 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000767
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768 this->internalRestore(); // restore the last, since we're going away
769
halcanary385fe4d2015-08-26 13:07:48 -0700770 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000771
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772 dec_canvas();
773}
774
fmalita53d9f1c2016-01-25 06:23:54 -0800775#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000776SkDrawFilter* SkCanvas::getDrawFilter() const {
777 return fMCRec->fFilter;
778}
779
780SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700781 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
783 return filter;
784}
fmalita77650002016-01-21 18:47:11 -0800785#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000786
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000787SkMetaData& SkCanvas::getMetaData() {
788 // metadata users are rare, so we lazily allocate it. If that changes we
789 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700790 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000791 fMetaData = new SkMetaData;
792 }
793 return *fMetaData;
794}
795
reed@android.com8a1c16f2008-12-17 15:59:43 +0000796///////////////////////////////////////////////////////////////////////////////
797
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000798void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700799 this->onFlush();
800}
801
802void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000803 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000804 if (device) {
805 device->flush();
806 }
807}
808
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000809SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000810 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000811 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
812}
813
senorblancoafc7cce2016-02-02 18:44:15 -0800814SkIRect SkCanvas::getTopLayerBounds() const {
815 SkBaseDevice* d = this->getTopDevice();
816 if (!d) {
817 return SkIRect::MakeEmpty();
818 }
819 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
820}
821
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000822SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000824 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825 SkASSERT(rec && rec->fLayer);
826 return rec->fLayer->fDevice;
827}
828
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000829SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000830 if (updateMatrixClip) {
831 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
832 }
reed@google.com9266fed2011-03-30 00:18:03 +0000833 return fMCRec->fTopLayer->fDevice;
834}
835
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000836bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700837 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000838 return false;
839 }
840
841 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700842 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700843 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000844 return false;
845 }
846 weAllocated = true;
847 }
848
reedcf01e312015-05-23 19:14:51 -0700849 SkAutoPixmapUnlock unlocker;
850 if (bitmap->requestLock(&unlocker)) {
851 const SkPixmap& pm = unlocker.pixmap();
852 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
853 return true;
854 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000855 }
856
857 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700858 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000859 }
860 return false;
861}
reed@google.com51df9e32010-12-23 19:29:18 +0000862
bsalomon@google.comc6980972011-11-02 19:57:21 +0000863bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000864 SkIRect r = srcRect;
865 const SkISize size = this->getBaseLayerSize();
866 if (!r.intersect(0, 0, size.width(), size.height())) {
867 bitmap->reset();
868 return false;
869 }
870
reed84825042014-09-02 12:50:45 -0700871 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000872 // bitmap will already be reset.
873 return false;
874 }
875 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
876 bitmap->reset();
877 return false;
878 }
879 return true;
880}
881
reed96472de2014-12-10 09:53:42 -0800882bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000883 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000884 if (!device) {
885 return false;
886 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000887 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800888
reed96472de2014-12-10 09:53:42 -0800889 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
890 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000891 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000892 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000893
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000894 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800895 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000896}
897
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000898bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700899 SkAutoPixmapUnlock unlocker;
900 if (bitmap.requestLock(&unlocker)) {
901 const SkPixmap& pm = unlocker.pixmap();
902 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000903 }
904 return false;
905}
906
907bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
908 int x, int y) {
909 switch (origInfo.colorType()) {
910 case kUnknown_SkColorType:
911 case kIndex_8_SkColorType:
912 return false;
913 default:
914 break;
915 }
halcanary96fcdcc2015-08-27 07:41:13 -0700916 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000917 return false;
918 }
919
920 const SkISize size = this->getBaseLayerSize();
921 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
922 if (!target.intersect(0, 0, size.width(), size.height())) {
923 return false;
924 }
925
926 SkBaseDevice* device = this->getDevice();
927 if (!device) {
928 return false;
929 }
930
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000931 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700932 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000933
934 // if x or y are negative, then we have to adjust pixels
935 if (x > 0) {
936 x = 0;
937 }
938 if (y > 0) {
939 y = 0;
940 }
941 // here x,y are either 0 or negative
942 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
943
reed4af35f32014-06-27 17:47:49 -0700944 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700945 const bool completeOverwrite = info.dimensions() == size;
946 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700947
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000948 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000949 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000950}
reed@google.com51df9e32010-12-23 19:29:18 +0000951
junov@google.com4370aed2012-01-18 16:21:08 +0000952SkCanvas* SkCanvas::canvasForDrawIter() {
953 return this;
954}
955
reed@android.com8a1c16f2008-12-17 15:59:43 +0000956//////////////////////////////////////////////////////////////////////////////
957
reed@android.com8a1c16f2008-12-17 15:59:43 +0000958void SkCanvas::updateDeviceCMCache() {
959 if (fDeviceCMDirty) {
960 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700961 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000963
halcanary96fcdcc2015-08-27 07:41:13 -0700964 if (nullptr == layer->fNext) { // only one layer
965 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000967 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968 do {
reed687fa1c2015-04-07 08:00:56 -0700969 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700970 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971 }
972 fDeviceCMDirty = false;
973 }
974}
975
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976///////////////////////////////////////////////////////////////////////////////
977
reed2ff1fce2014-12-11 07:07:37 -0800978void SkCanvas::checkForDeferredSave() {
979 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800980 this->doSave();
981 }
982}
983
reedf0090cb2014-11-26 08:55:51 -0800984int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800985#ifdef SK_DEBUG
986 int count = 0;
987 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
988 for (;;) {
989 const MCRec* rec = (const MCRec*)iter.next();
990 if (!rec) {
991 break;
992 }
993 count += 1 + rec->fDeferredSaveCount;
994 }
995 SkASSERT(count == fSaveCount);
996#endif
997 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800998}
999
1000int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001001 fSaveCount += 1;
1002 fMCRec->fDeferredSaveCount += 1;
1003 return this->getSaveCount() - 1; // return our prev value
1004}
1005
1006void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001007 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001008
1009 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1010 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001011 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001012}
1013
1014void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001015 if (fMCRec->fDeferredSaveCount > 0) {
1016 SkASSERT(fSaveCount > 1);
1017 fSaveCount -= 1;
1018 fMCRec->fDeferredSaveCount -= 1;
1019 } else {
1020 // check for underflow
1021 if (fMCStack.count() > 1) {
1022 this->willRestore();
1023 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001024 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001025 this->internalRestore();
1026 this->didRestore();
1027 }
reedf0090cb2014-11-26 08:55:51 -08001028 }
1029}
1030
1031void SkCanvas::restoreToCount(int count) {
1032 // sanity check
1033 if (count < 1) {
1034 count = 1;
1035 }
mtkleinf0f14112014-12-12 08:46:25 -08001036
reedf0090cb2014-11-26 08:55:51 -08001037 int n = this->getSaveCount() - count;
1038 for (int i = 0; i < n; ++i) {
1039 this->restore();
1040 }
1041}
1042
reed2ff1fce2014-12-11 07:07:37 -08001043void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001044 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001045 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001046 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001047
reed687fa1c2015-04-07 08:00:56 -07001048 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001049}
1050
reed4960eee2015-12-18 07:09:18 -08001051bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001052#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001053 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@google.comb93ba452014-03-10 19:47:58 +00001054#else
1055 return true;
1056#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001057}
1058
reed4960eee2015-12-18 07:09:18 -08001059bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001060 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001061 SkIRect clipBounds;
1062 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001063 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001064 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001065
reed96e657d2015-03-10 17:30:07 -07001066 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1067
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001068 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001069 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001070 if (bounds && !imageFilter->canComputeFastBounds()) {
1071 bounds = nullptr;
1072 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001073 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001074 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001075 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001076 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001077
reed96e657d2015-03-10 17:30:07 -07001078 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001079 r.roundOut(&ir);
1080 // early exit if the layer's bounds are clipped out
1081 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001082 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001083 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001084 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001085 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001086 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 }
1088 } else { // no user bounds, so just use the clip
1089 ir = clipBounds;
1090 }
reed180aec42015-03-11 10:39:04 -07001091 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001092
reed4960eee2015-12-18 07:09:18 -08001093 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001094 // Simplify the current clips since they will be applied properly during restore()
reed687fa1c2015-04-07 08:00:56 -07001095 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001096 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001097 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001098 }
1099
1100 if (intersection) {
1101 *intersection = ir;
1102 }
1103 return true;
1104}
1105
reed4960eee2015-12-18 07:09:18 -08001106
reed4960eee2015-12-18 07:09:18 -08001107int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1108 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001109}
1110
reed70ee31b2015-12-10 13:44:45 -08001111int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001112 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1113}
1114
1115int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1116 SaveLayerRec rec(origRec);
1117 if (gIgnoreSaveLayerBounds) {
1118 rec.fBounds = nullptr;
1119 }
1120 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1121 fSaveCount += 1;
1122 this->internalSaveLayer(rec, strategy);
1123 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001124}
1125
reeda2217ef2016-07-20 06:04:34 -07001126void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1127 SkBaseDevice* dst, const SkMatrix& ctm,
1128 const SkClipStack* clipStack) {
1129 SkDraw draw;
1130 SkRasterClip rc;
1131 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1132 if (!dst->accessPixels(&draw.fDst)) {
1133 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001134 }
reeda2217ef2016-07-20 06:04:34 -07001135 draw.fMatrix = &SkMatrix::I();
1136 draw.fRC = &rc;
1137 draw.fClipStack = clipStack;
1138 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001139
1140 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001141 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001142
1143 int x = src->getOrigin().x() - dst->getOrigin().x();
1144 int y = src->getOrigin().y() - dst->getOrigin().y();
1145 auto special = src->snapSpecial();
1146 if (special) {
1147 dst->drawSpecial(draw, special.get(), x, y, p);
1148 }
robertphillips7354a4b2015-12-16 05:08:27 -08001149}
reed70ee31b2015-12-10 13:44:45 -08001150
reed129ed1c2016-02-22 06:42:31 -08001151static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1152 const SkPaint* paint) {
1153 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1154 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001155 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001156 const bool hasImageFilter = paint && paint->getImageFilter();
1157
1158 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1159 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1160 // force to L32
1161 return SkImageInfo::MakeN32(w, h, alphaType);
1162 } else {
1163 // keep the same characteristics as the prev
brianosman52ede1d2016-06-20 08:25:02 -07001164 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace()));
reed129ed1c2016-02-22 06:42:31 -08001165 }
1166}
1167
reed4960eee2015-12-18 07:09:18 -08001168void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1169 const SkRect* bounds = rec.fBounds;
1170 const SkPaint* paint = rec.fPaint;
1171 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1172
reed@google.comb93ba452014-03-10 19:47:58 +00001173#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001174 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001175#endif
1176
reed8c30a812016-04-20 16:36:51 -07001177 SkLazyPaint lazyP;
1178 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1179 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001180 SkMatrix remainder;
1181 SkSize scale;
1182 /*
1183 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1184 * but they do handle scaling. To accommodate this, we do the following:
1185 *
1186 * 1. Stash off the current CTM
1187 * 2. Decompose the CTM into SCALE and REMAINDER
1188 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1189 * contains the REMAINDER
1190 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1191 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1192 * of the original imagefilter, and draw that (via drawSprite)
1193 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1194 *
1195 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1196 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1197 */
reed96a04f32016-04-25 09:25:15 -07001198 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001199 stashedMatrix.decomposeScale(&scale, &remainder))
1200 {
1201 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1202 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1203 SkPaint* p = lazyP.set(*paint);
1204 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1205 SkFilterQuality::kLow_SkFilterQuality,
1206 sk_ref_sp(imageFilter)));
1207 imageFilter = p->getImageFilter();
1208 paint = p;
1209 }
reed8c30a812016-04-20 16:36:51 -07001210
junov@chromium.orga907ac32012-02-24 21:54:07 +00001211 // do this before we create the layer. We don't call the public save() since
1212 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001213 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001214
1215 fDeviceCMDirty = true;
1216
1217 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001218 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001219 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001220 }
1221
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001222 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1223 // the clipRectBounds() call above?
1224 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001225 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001226 }
1227
reed4960eee2015-12-18 07:09:18 -08001228 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001229 SkPixelGeometry geo = fProps.pixelGeometry();
1230 if (paint) {
reed76033be2015-03-14 10:54:31 -07001231 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001232 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001233 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001234 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001235 }
1236 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001237
robertphillips5139e502016-07-19 05:10:40 -07001238 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001239 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001240 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001241 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001242 }
reedb2db8982014-11-13 12:41:02 -08001243
robertphillips5139e502016-07-19 05:10:40 -07001244 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001245 paint);
1246
robertphillips5139e502016-07-19 05:10:40 -07001247 SkAutoTUnref<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001248 {
reed70ee31b2015-12-10 13:44:45 -08001249 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001250 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001251 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001252 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
reedcd4051e2016-07-15 09:41:26 -07001253 preserveLCDText);
robertphillips5139e502016-07-19 05:10:40 -07001254 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1255 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001256 SkErrorInternals::SetError(kInternalError_SkError,
1257 "Unable to create device for layer.");
1258 return;
reed61f501f2015-04-29 08:34:00 -07001259 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001260 }
robertphillips5139e502016-07-19 05:10:40 -07001261 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001262
robertphillips5139e502016-07-19 05:10:40 -07001263 DeviceCM* layer = new DeviceCM(newDevice, paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001264
1265 layer->fNext = fMCRec->fTopLayer;
1266 fMCRec->fLayer = layer;
1267 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001268
1269 if (rec.fBackdrop) {
1270 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice,
1271 fMCRec->fMatrix, this->getClipStack());
1272 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273}
1274
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001275int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001276 if (0xFF == alpha) {
1277 return this->saveLayer(bounds, nullptr);
1278 } else {
1279 SkPaint tmpPaint;
1280 tmpPaint.setAlpha(alpha);
1281 return this->saveLayer(bounds, &tmpPaint);
1282 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001283}
1284
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285void SkCanvas::internalRestore() {
1286 SkASSERT(fMCStack.count() != 0);
1287
1288 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289
reed687fa1c2015-04-07 08:00:56 -07001290 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001291
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001292 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293 DeviceCM* layer = fMCRec->fLayer; // may be null
1294 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001295 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296
1297 // now do the normal restore()
1298 fMCRec->~MCRec(); // balanced in save()
1299 fMCStack.pop_back();
1300 fMCRec = (MCRec*)fMCStack.back();
1301
1302 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1303 since if we're being recorded, we don't want to record this (the
1304 recorder will have already recorded the restore).
1305 */
bsalomon49f085d2014-09-05 13:34:00 -07001306 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001307 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001308 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001309 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001310 // restore what we smashed in internalSaveLayer
1311 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001312 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001314 delete layer;
reedb679ca82015-04-07 04:40:48 -07001315 } else {
1316 // we're at the root
reeda499f902015-05-01 09:34:31 -07001317 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001318 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001319 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001320 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001321 }
msarettfbfa2582016-08-12 08:29:08 -07001322
1323 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001324 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001325 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1326 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001327}
1328
reede8f30622016-03-23 18:59:25 -07001329sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001330 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001331 props = &fProps;
1332 }
1333 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001334}
1335
reede8f30622016-03-23 18:59:25 -07001336sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001337 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001338 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001339}
1340
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001341SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001342 return this->onImageInfo();
1343}
1344
1345SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001346 SkBaseDevice* dev = this->getDevice();
1347 if (dev) {
1348 return dev->imageInfo();
1349 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001350 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001351 }
1352}
1353
brianosman898235c2016-04-06 07:38:23 -07001354bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001355 return this->onGetProps(props);
1356}
1357
1358bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001359 SkBaseDevice* dev = this->getDevice();
1360 if (dev) {
1361 if (props) {
1362 *props = fProps;
1363 }
1364 return true;
1365 } else {
1366 return false;
1367 }
1368}
1369
reed6ceeebd2016-03-09 14:26:26 -08001370#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001371const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001372 SkPixmap pmap;
reed6ceeebd2016-03-09 14:26:26 -08001373 if (this->peekPixels(&pmap)) {
1374 if (info) {
1375 *info = pmap.info();
1376 }
1377 if (rowBytes) {
1378 *rowBytes = pmap.rowBytes();
1379 }
1380 return pmap.addr();
reed884e97c2015-05-26 11:31:54 -07001381 }
reed6ceeebd2016-03-09 14:26:26 -08001382 return nullptr;
1383}
1384#endif
1385
1386bool SkCanvas::peekPixels(SkPixmap* pmap) {
1387 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001388}
1389
reed884e97c2015-05-26 11:31:54 -07001390bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001391 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001392 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001393}
1394
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001395void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001396 SkPixmap pmap;
1397 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001398 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001399 }
1400 if (info) {
1401 *info = pmap.info();
1402 }
1403 if (rowBytes) {
1404 *rowBytes = pmap.rowBytes();
1405 }
1406 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001407 *origin = this->getTopDevice(false)->getOrigin();
1408 }
reed884e97c2015-05-26 11:31:54 -07001409 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001410}
1411
reed884e97c2015-05-26 11:31:54 -07001412bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001413 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001414 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001415}
1416
reed@android.com8a1c16f2008-12-17 15:59:43 +00001417/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418
reed7503d602016-07-15 14:23:29 -07001419void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001421 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422 paint = &tmp;
1423 }
reed@google.com4b226022011-01-11 18:32:13 +00001424
reed@google.com8926b162012-03-23 15:36:36 +00001425 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001426
reed@android.com8a1c16f2008-12-17 15:59:43 +00001427 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001428 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001429 paint = &looper.paint();
1430 SkImageFilter* filter = paint->getImageFilter();
1431 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
senorblancof35566e2016-04-18 10:32:02 -07001432 if (filter) {
reeda2217ef2016-07-20 06:04:34 -07001433 dstDev->drawSpecial(iter, srcDev->snapSpecial().get(), pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001434 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001435 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001436 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001437 }
reeda2217ef2016-07-20 06:04:34 -07001438
reed@google.com4e2b3d32011-04-07 14:18:59 +00001439 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001440}
1441
reed32704672015-12-16 08:27:10 -08001442/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001443
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001444void SkCanvas::translate(SkScalar dx, SkScalar dy) {
mtkleincbdf0072016-08-19 09:05:27 -07001445 this->checkForDeferredSave();
1446 fDeviceCMDirty = true;
1447 fMCRec->fMatrix.preTranslate(dx,dy);
1448
1449 // Translate shouldn't affect the is-scale-translateness of the matrix.
1450 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
1451
1452 this->didTranslate(dx,dy);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001453}
1454
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001455void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001456 SkMatrix m;
1457 m.setScale(sx, sy);
1458 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001459}
1460
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001461void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001462 SkMatrix m;
1463 m.setRotate(degrees);
1464 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001465}
1466
bungeman7438bfc2016-07-12 15:01:19 -07001467void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1468 SkMatrix m;
1469 m.setRotate(degrees, px, py);
1470 this->concat(m);
1471}
1472
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001473void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001474 SkMatrix m;
1475 m.setSkew(sx, sy);
1476 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001477}
1478
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001479void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001480 if (matrix.isIdentity()) {
1481 return;
1482 }
1483
reed2ff1fce2014-12-11 07:07:37 -08001484 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001485 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001486 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001487 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001488 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001489}
1490
reed8c30a812016-04-20 16:36:51 -07001491void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001492 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001493 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001494 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001495}
1496
1497void SkCanvas::setMatrix(const SkMatrix& matrix) {
1498 this->checkForDeferredSave();
1499 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001500 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501}
1502
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001504 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001505}
1506
vjiaoblack95302da2016-07-21 10:25:54 -07001507#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001508void SkCanvas::translateZ(SkScalar z) {
1509 this->checkForDeferredSave();
1510 this->fMCRec->fCurDrawDepth += z;
1511 this->didTranslateZ(z);
1512}
1513
1514SkScalar SkCanvas::getZ() const {
1515 return this->fMCRec->fCurDrawDepth;
1516}
1517
vjiaoblack95302da2016-07-21 10:25:54 -07001518void SkCanvas::setLights(sk_sp<SkLights> lights) {
1519 this->fLights = lights;
1520}
1521
1522sk_sp<SkLights> SkCanvas::getLights() const {
1523 return this->fLights;
1524}
1525#endif
1526
reed@android.com8a1c16f2008-12-17 15:59:43 +00001527//////////////////////////////////////////////////////////////////////////////
1528
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001529void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2d1afab2016-06-29 14:33:11 -07001530 if (!fAllowSoftClip) {
1531 doAA = false;
1532 }
1533
1534#ifdef SK_SUPPORT_PRECHECK_CLIPRECT
1535 // Check if we can quick-accept the clip call (and do nothing)
1536 //
reed74467162016-06-30 08:15:35 -07001537 if (SkRegion::kIntersect_Op == op && !doAA && fMCRec->fMatrix.isScaleTranslate()) {
halcanaryc5769b22016-08-10 07:13:21 -07001538 SkRect devR;
1539 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect);
reed2d1afab2016-06-29 14:33:11 -07001540 // NOTE: this check is CTM specific, since we might round differently with a different
1541 // CTM. Thus this is only 100% reliable if there is not global CTM scale to be
1542 // applied later (i.e. if this is going into a picture).
1543 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1544#if 0
1545 SkDebugf("ignored clipRect [%g %g %g %g]\n",
1546 rect.left(), rect.top(), rect.right(), rect.bottom());
1547#endif
1548 return;
1549 }
1550 }
1551#endif
1552
reed2ff1fce2014-12-11 07:07:37 -08001553 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001554 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1555 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001556}
1557
1558void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001559#ifdef SK_ENABLE_CLIP_QUICKREJECT
1560 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001561 if (fMCRec->fRasterClip.isEmpty()) {
reed2d1afab2016-06-29 14:33:11 -07001562 return;
reed@google.comda17f752012-08-16 18:27:05 +00001563 }
1564
reed@google.com3b3e8952012-08-16 20:53:31 +00001565 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001566 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001567 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001568
reed687fa1c2015-04-07 08:00:56 -07001569 fClipStack->clipEmpty();
reed2d1afab2016-06-29 14:33:11 -07001570 (void)fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001571 fDeviceClipBounds.setEmpty();
reed2d1afab2016-06-29 14:33:11 -07001572 return;
reed@google.comda17f752012-08-16 18:27:05 +00001573 }
1574 }
1575#endif
1576
reed74467162016-06-30 08:15:35 -07001577 const bool isScaleTrans = fMCRec->fMatrix.isScaleTranslate();
reedc64eff52015-11-21 12:39:45 -08001578 SkRect devR;
reed74467162016-06-30 08:15:35 -07001579 if (isScaleTrans) {
halcanaryc5769b22016-08-10 07:13:21 -07001580 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect);
reedc64eff52015-11-21 12:39:45 -08001581 }
bsalomonac8cabd2015-11-20 18:53:07 -08001582
reed2d1afab2016-06-29 14:33:11 -07001583#ifndef SK_SUPPORT_PRECHECK_CLIPRECT
reedc64eff52015-11-21 12:39:45 -08001584 if (SkRegion::kIntersect_Op == op &&
1585 kHard_ClipEdgeStyle == edgeStyle
reed74467162016-06-30 08:15:35 -07001586 && isScaleTrans)
reedc64eff52015-11-21 12:39:45 -08001587 {
1588 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1589#if 0
1590 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1591 rect.left(), rect.top(), rect.right(), rect.bottom());
1592#endif
1593 return;
1594 }
1595 }
reed2d1afab2016-06-29 14:33:11 -07001596#endif
reedc64eff52015-11-21 12:39:45 -08001597
1598 AutoValidateClip avc(this);
1599
1600 fDeviceCMDirty = true;
reedc64eff52015-11-21 12:39:45 -08001601
reed74467162016-06-30 08:15:35 -07001602 if (isScaleTrans) {
reedc64eff52015-11-21 12:39:45 -08001603 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1604 fClipStack->clipDevRect(devR, op, isAA);
senorblancoafc7cce2016-02-02 18:44:15 -08001605 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001606 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001607 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001608 // and clip against that, since it can handle any matrix. However, to
1609 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1610 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001611 SkPath path;
1612
1613 path.addRect(rect);
bsalomonbdc335f2016-08-22 13:42:17 -07001614 path.setIsVolatile(true);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001615 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001616 }
msarettfbfa2582016-08-12 08:29:08 -07001617
1618 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001619}
1620
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001621void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001622 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001623 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001624 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001625 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1626 } else {
1627 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001628 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001629}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001630
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001631void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001632 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001633 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001634 AutoValidateClip avc(this);
1635
1636 fDeviceCMDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001637 if (!fAllowSoftClip) {
1638 edgeStyle = kHard_ClipEdgeStyle;
1639 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001640
reed687fa1c2015-04-07 08:00:56 -07001641 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001642
senorblancoafc7cce2016-02-02 18:44:15 -08001643 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
robertphillips125f19a2015-11-23 09:00:05 -08001644 kSoft_ClipEdgeStyle == edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001645 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001646 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001647 }
1648
1649 SkPath path;
1650 path.addRRect(rrect);
bsalomonbdc335f2016-08-22 13:42:17 -07001651 path.setIsVolatile(true);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001652 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001653 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001654}
1655
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001656void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001657 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001658 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001659
1660 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1661 SkRect r;
1662 if (path.isRect(&r)) {
1663 this->onClipRect(r, op, edgeStyle);
1664 return;
1665 }
1666 SkRRect rrect;
1667 if (path.isOval(&r)) {
1668 rrect.setOval(r);
1669 this->onClipRRect(rrect, op, edgeStyle);
1670 return;
1671 }
1672 if (path.isRRect(&rrect)) {
1673 this->onClipRRect(rrect, op, edgeStyle);
1674 return;
1675 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001676 }
robertphillips39f05382015-11-24 09:30:12 -08001677
1678 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001679}
1680
1681void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001682#ifdef SK_ENABLE_CLIP_QUICKREJECT
1683 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001684 if (fMCRec->fRasterClip.isEmpty()) {
reed2d1afab2016-06-29 14:33:11 -07001685 return;
reed@google.comda17f752012-08-16 18:27:05 +00001686 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001687
reed@google.com3b3e8952012-08-16 20:53:31 +00001688 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001689 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001690 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001691
reed687fa1c2015-04-07 08:00:56 -07001692 fClipStack->clipEmpty();
reed2d1afab2016-06-29 14:33:11 -07001693 (void)fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001694 fDeviceClipBounds.setEmpty();
reed2d1afab2016-06-29 14:33:11 -07001695 return;
reed@google.comda17f752012-08-16 18:27:05 +00001696 }
1697 }
1698#endif
1699
reed@google.com5c3d1472011-02-22 19:12:23 +00001700 AutoValidateClip avc(this);
1701
reed@android.com8a1c16f2008-12-17 15:59:43 +00001702 fDeviceCMDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001703 if (!fAllowSoftClip) {
1704 edgeStyle = kHard_ClipEdgeStyle;
1705 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001706
1707 SkPath devPath;
bsalomonbdc335f2016-08-22 13:42:17 -07001708 if (fMCRec->fMatrix.isIdentity()) {
1709 devPath = path;
1710 } else {
1711 path.transform(fMCRec->fMatrix, &devPath);
1712 devPath.setIsVolatile(true);
1713 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001714
reed@google.comfe701122011-11-08 19:41:23 +00001715 // Check if the transfomation, or the original path itself
1716 // made us empty. Note this can also happen if we contained NaN
1717 // values. computing the bounds detects this, and will set our
1718 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1719 if (devPath.getBounds().isEmpty()) {
1720 // resetting the path will remove any NaN or other wanky values
1721 // that might upset our scan converter.
1722 devPath.reset();
1723 }
1724
reed@google.com5c3d1472011-02-22 19:12:23 +00001725 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001726 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001727
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001728 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001729 bool clipIsAA = getClipStack()->asPath(&devPath);
1730 if (clipIsAA) {
1731 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001732 }
fmalita1a481fe2015-02-04 07:39:34 -08001733
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001734 op = SkRegion::kReplace_Op;
1735 }
1736
senorblancoafc7cce2016-02-02 18:44:15 -08001737 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001738 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001739}
1740
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001741void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001742 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001743 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001744}
1745
1746void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001747 AutoValidateClip avc(this);
1748
reed@android.com8a1c16f2008-12-17 15:59:43 +00001749 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001750
reed@google.com5c3d1472011-02-22 19:12:23 +00001751 // todo: signal fClipStack that we have a region, and therefore (I guess)
1752 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001753 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001754
reed1f836ee2014-07-07 07:49:34 -07001755 fMCRec->fRasterClip.op(rgn, op);
msarettfbfa2582016-08-12 08:29:08 -07001756 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001757}
1758
reed@google.com819c9212011-02-23 18:56:55 +00001759#ifdef SK_DEBUG
1760void SkCanvas::validateClip() const {
1761 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001762 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001763 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001764 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001765 return;
1766 }
1767
reed@google.com819c9212011-02-23 18:56:55 +00001768 SkIRect ir;
1769 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001770 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001771
reed687fa1c2015-04-07 08:00:56 -07001772 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001773 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001774 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001775 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001776 case SkClipStack::Element::kRect_Type:
1777 element->getRect().round(&ir);
1778 tmpClip.op(ir, element->getOp());
1779 break;
1780 case SkClipStack::Element::kEmpty_Type:
1781 tmpClip.setEmpty();
1782 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001783 default: {
1784 SkPath path;
1785 element->asPath(&path);
senorblancoafc7cce2016-02-02 18:44:15 -08001786 tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001787 break;
1788 }
reed@google.com819c9212011-02-23 18:56:55 +00001789 }
1790 }
reed@google.com819c9212011-02-23 18:56:55 +00001791}
1792#endif
1793
reed@google.com90c07ea2012-04-13 13:50:27 +00001794void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001795 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001796 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001797
halcanary96fcdcc2015-08-27 07:41:13 -07001798 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001799 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001800 }
1801}
1802
reed@google.com5c3d1472011-02-22 19:12:23 +00001803///////////////////////////////////////////////////////////////////////////////
1804
reed@google.com754de5f2014-02-24 19:38:20 +00001805bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001806 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001807}
1808
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001809bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001810 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001811}
1812
msarettfbfa2582016-08-12 08:29:08 -07001813static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1814#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1815 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1816 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1817 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1818 return 0xF != _mm_movemask_ps(mask);
1819#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1820 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1821 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1822 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1823 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1824#else
1825 SkRect devRectAsRect;
1826 SkRect devClipAsRect;
1827 devRect.store(&devRectAsRect.fLeft);
1828 devClip.store(&devClipAsRect.fLeft);
1829 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1830#endif
1831}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001832
msarettfbfa2582016-08-12 08:29:08 -07001833// It's important for this function to not be inlined. Otherwise the compiler will share code
1834// between the fast path and the slow path, resulting in two slow paths.
1835static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1836 const SkMatrix& matrix) {
1837 SkRect deviceRect;
1838 matrix.mapRect(&deviceRect, src);
1839 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1840}
1841
1842bool SkCanvas::quickReject(const SkRect& src) const {
1843#ifdef SK_DEBUG
1844 // Verify that fDeviceClipBounds are set properly.
1845 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001846 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001847 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001848 } else {
msarettfbfa2582016-08-12 08:29:08 -07001849 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001850 }
msarettfbfa2582016-08-12 08:29:08 -07001851
msarett9637ea92016-08-18 14:03:30 -07001852 // Verify that fIsScaleTranslate is set properly.
1853 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001854#endif
1855
msarett9637ea92016-08-18 14:03:30 -07001856 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001857 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1858 }
1859
1860 // We inline the implementation of mapScaleTranslate() for the fast path.
1861 float sx = fMCRec->fMatrix.getScaleX();
1862 float sy = fMCRec->fMatrix.getScaleY();
1863 float tx = fMCRec->fMatrix.getTranslateX();
1864 float ty = fMCRec->fMatrix.getTranslateY();
1865 Sk4f scale(sx, sy, sx, sy);
1866 Sk4f trans(tx, ty, tx, ty);
1867
1868 // Apply matrix.
1869 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1870
1871 // Make sure left < right, top < bottom.
1872 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1873 Sk4f min = Sk4f::Min(ltrb, rblt);
1874 Sk4f max = Sk4f::Max(ltrb, rblt);
1875 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1876 // ARM this sequence generates the fastest (a single instruction).
1877 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1878
1879 // Check if the device rect is NaN or outside the clip.
1880 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001881}
1882
reed@google.com3b3e8952012-08-16 20:53:31 +00001883bool SkCanvas::quickReject(const SkPath& path) const {
1884 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001885}
1886
reed@google.com3b3e8952012-08-16 20:53:31 +00001887bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001888 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001889 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001890 return false;
1891 }
1892
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001893 SkMatrix inverse;
1894 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001895 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001896 if (bounds) {
1897 bounds->setEmpty();
1898 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001899 return false;
1900 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001901
bsalomon49f085d2014-09-05 13:34:00 -07001902 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001903 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001904 // adjust it outwards in case we are antialiasing
1905 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001906
reed@google.com8f4d2302013-12-17 16:44:46 +00001907 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1908 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001909 inverse.mapRect(bounds, r);
1910 }
1911 return true;
1912}
1913
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001914bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001915 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001916 if (clip.isEmpty()) {
1917 if (bounds) {
1918 bounds->setEmpty();
1919 }
1920 return false;
1921 }
1922
bsalomon49f085d2014-09-05 13:34:00 -07001923 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001924 *bounds = clip.getBounds();
1925 }
1926 return true;
1927}
1928
reed@android.com8a1c16f2008-12-17 15:59:43 +00001929const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001930 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001931}
1932
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001933const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001934 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001935}
1936
robertphillips175dd9b2016-04-28 14:32:04 -07001937GrDrawContext* SkCanvas::internal_private_accessTopLayerDrawContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001938 SkBaseDevice* dev = this->getTopDevice();
robertphillips175dd9b2016-04-28 14:32:04 -07001939 return dev ? dev->accessDrawContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001940}
1941
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001942GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001943 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001944 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001945}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001946
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001947void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1948 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001949 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001950 if (outer.isEmpty()) {
1951 return;
1952 }
1953 if (inner.isEmpty()) {
1954 this->drawRRect(outer, paint);
1955 return;
1956 }
1957
1958 // We don't have this method (yet), but technically this is what we should
1959 // be able to assert...
1960 // SkASSERT(outer.contains(inner));
1961 //
1962 // For now at least check for containment of bounds
1963 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1964
1965 this->onDrawDRRect(outer, inner, paint);
1966}
1967
reed41af9662015-01-05 07:49:08 -08001968// These need to stop being virtual -- clients need to override the onDraw... versions
1969
1970void SkCanvas::drawPaint(const SkPaint& paint) {
1971 this->onDrawPaint(paint);
1972}
1973
1974void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1975 this->onDrawRect(r, paint);
1976}
1977
msarettdca352e2016-08-26 06:37:45 -07001978void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1979 if (region.isEmpty()) {
1980 return;
1981 }
1982
1983 if (region.isRect()) {
1984 return this->drawIRect(region.getBounds(), paint);
1985 }
1986
1987 this->onDrawRegion(region, paint);
1988}
1989
reed41af9662015-01-05 07:49:08 -08001990void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1991 this->onDrawOval(r, paint);
1992}
1993
1994void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1995 this->onDrawRRect(rrect, paint);
1996}
1997
1998void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1999 this->onDrawPoints(mode, count, pts, paint);
2000}
2001
2002void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
2003 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
2004 const uint16_t indices[], int indexCount, const SkPaint& paint) {
2005 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
2006 indices, indexCount, paint);
2007}
2008
2009void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
2010 this->onDrawPath(path, paint);
2011}
2012
reeda85d4d02015-05-06 12:56:48 -07002013void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002014 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07002015 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08002016}
2017
reede47829b2015-08-06 10:02:53 -07002018void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
2019 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002020 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002021 if (dst.isEmpty() || src.isEmpty()) {
2022 return;
2023 }
2024 this->onDrawImageRect(image, &src, dst, paint, constraint);
2025}
reed41af9662015-01-05 07:49:08 -08002026
reed84984ef2015-07-17 07:09:43 -07002027void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
2028 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002029 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002030 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002031}
2032
reede47829b2015-08-06 10:02:53 -07002033void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
2034 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002035 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002036 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
2037 constraint);
2038}
reede47829b2015-08-06 10:02:53 -07002039
reed4c21dc52015-06-25 12:32:03 -07002040void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2041 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002042 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07002043 if (dst.isEmpty()) {
2044 return;
2045 }
msarett552bca92016-08-03 06:53:26 -07002046 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
2047 this->onDrawImageNine(image, center, dst, paint);
2048 } else {
reede47829b2015-08-06 10:02:53 -07002049 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002050 }
reed4c21dc52015-06-25 12:32:03 -07002051}
2052
msarett16882062016-08-16 09:31:08 -07002053void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2054 const SkPaint* paint) {
2055 RETURN_ON_NULL(image);
2056 if (dst.isEmpty()) {
2057 return;
2058 }
2059 if (SkLatticeIter::Valid(image->width(), image->height(), lattice)) {
2060 this->onDrawImageLattice(image, lattice, dst, paint);
2061 } else {
2062 this->drawImageRect(image, dst, paint);
2063 }
2064}
2065
reed41af9662015-01-05 07:49:08 -08002066void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002067 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002068 return;
2069 }
reed41af9662015-01-05 07:49:08 -08002070 this->onDrawBitmap(bitmap, dx, dy, paint);
2071}
2072
reede47829b2015-08-06 10:02:53 -07002073void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002074 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002075 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002076 return;
2077 }
reede47829b2015-08-06 10:02:53 -07002078 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002079}
2080
reed84984ef2015-07-17 07:09:43 -07002081void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2082 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002083 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002084}
2085
reede47829b2015-08-06 10:02:53 -07002086void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2087 SrcRectConstraint constraint) {
2088 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2089 constraint);
2090}
reede47829b2015-08-06 10:02:53 -07002091
reed41af9662015-01-05 07:49:08 -08002092void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2093 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002094 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002095 return;
2096 }
msarett552bca92016-08-03 06:53:26 -07002097 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2098 this->onDrawBitmapNine(bitmap, center, dst, paint);
2099 } else {
reeda5517e22015-07-14 10:54:12 -07002100 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002101 }
reed41af9662015-01-05 07:49:08 -08002102}
2103
msarettc573a402016-08-02 08:05:56 -07002104void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2105 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002106 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002107 return;
2108 }
msarett16882062016-08-16 09:31:08 -07002109 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), lattice)) {
2110 this->onDrawBitmapLattice(bitmap, lattice, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002111 } else {
msarett16882062016-08-16 09:31:08 -07002112 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002113 }
msarettc573a402016-08-02 08:05:56 -07002114}
2115
reed71c3c762015-06-24 10:29:17 -07002116void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2117 const SkColor colors[], int count, SkXfermode::Mode mode,
2118 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002119 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002120 if (count <= 0) {
2121 return;
2122 }
2123 SkASSERT(atlas);
2124 SkASSERT(xform);
2125 SkASSERT(tex);
2126 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2127}
2128
reedf70b5312016-03-04 16:36:20 -08002129void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2130 if (key) {
2131 this->onDrawAnnotation(rect, key, value);
2132 }
2133}
2134
reede47829b2015-08-06 10:02:53 -07002135void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2136 const SkPaint* paint, SrcRectConstraint constraint) {
2137 if (src) {
2138 this->drawImageRect(image, *src, dst, paint, constraint);
2139 } else {
2140 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2141 dst, paint, constraint);
2142 }
2143}
2144void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2145 const SkPaint* paint, SrcRectConstraint constraint) {
2146 if (src) {
2147 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2148 } else {
2149 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2150 dst, paint, constraint);
2151 }
2152}
2153
tomhudsoncb3bd182016-05-18 07:24:16 -07002154void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2155 SkIRect layer_bounds = this->getTopLayerBounds();
2156 if (matrix) {
2157 *matrix = this->getTotalMatrix();
2158 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2159 }
2160 if (clip_bounds) {
2161 this->getClipDeviceBounds(clip_bounds);
2162 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2163 }
2164}
2165
reed@android.com8a1c16f2008-12-17 15:59:43 +00002166//////////////////////////////////////////////////////////////////////////////
2167// These are the virtual drawing methods
2168//////////////////////////////////////////////////////////////////////////////
2169
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002170void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002171 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002172 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2173 }
2174}
2175
reed41af9662015-01-05 07:49:08 -08002176void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002177 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002178 this->internalDrawPaint(paint);
2179}
2180
2181void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002182 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002183
2184 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002185 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002186 }
2187
reed@google.com4e2b3d32011-04-07 14:18:59 +00002188 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002189}
2190
reed41af9662015-01-05 07:49:08 -08002191void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2192 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002193 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002194 if ((long)count <= 0) {
2195 return;
2196 }
2197
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002198 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002199 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002200 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002201 // special-case 2 points (common for drawing a single line)
2202 if (2 == count) {
2203 r.set(pts[0], pts[1]);
2204 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002205 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002206 }
senorblanco87e066e2015-10-28 11:23:36 -07002207 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2208 return;
2209 }
2210 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002211 }
reed@google.coma584aed2012-05-16 14:06:02 +00002212
halcanary96fcdcc2015-08-27 07:41:13 -07002213 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002214
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002215 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002216
reed@android.com8a1c16f2008-12-17 15:59:43 +00002217 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002218 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002219 }
reed@google.com4b226022011-01-11 18:32:13 +00002220
reed@google.com4e2b3d32011-04-07 14:18:59 +00002221 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002222}
2223
reed4a167172016-08-18 17:15:25 -07002224static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2225 return ((intptr_t)paint.getImageFilter() |
2226#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2227 (intptr_t)canvas->getDrawFilter() |
2228#endif
2229 (intptr_t)paint.getLooper() ) != 0;
2230}
2231
reed41af9662015-01-05 07:49:08 -08002232void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002233 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002234 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002235 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002236 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002237 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2238 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2239 SkRect tmp(r);
2240 tmp.sort();
2241
senorblanco87e066e2015-10-28 11:23:36 -07002242 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2243 return;
2244 }
2245 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002246 }
reed@google.com4b226022011-01-11 18:32:13 +00002247
reed4a167172016-08-18 17:15:25 -07002248 if (needs_autodrawlooper(this, paint)) {
2249 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002250
reed4a167172016-08-18 17:15:25 -07002251 while (iter.next()) {
2252 iter.fDevice->drawRect(iter, r, looper.paint());
2253 }
2254
2255 LOOPER_END
2256 } else {
2257 this->predrawNotify(bounds, &paint, false);
2258 SkDrawIter iter(this);
2259 while (iter.next()) {
2260 iter.fDevice->drawRect(iter, r, paint);
2261 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002262 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002263}
2264
msarett44df6512016-08-25 13:54:30 -07002265void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2266 SkRect storage;
2267 SkRect regionRect = SkRect::Make(region.getBounds());
2268 const SkRect* bounds = nullptr;
2269 if (paint.canComputeFastBounds()) {
2270 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2271 return;
2272 }
2273 bounds = &regionRect;
2274 }
2275
2276 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2277
2278 while (iter.next()) {
2279 iter.fDevice->drawRegion(iter, region, looper.paint());
2280 }
2281
2282 LOOPER_END
2283}
2284
reed41af9662015-01-05 07:49:08 -08002285void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002286 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002287 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002288 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002289 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002290 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2291 return;
2292 }
2293 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002294 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002295
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002296 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002297
2298 while (iter.next()) {
2299 iter.fDevice->drawOval(iter, oval, looper.paint());
2300 }
2301
2302 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002303}
2304
bsalomonac3aa242016-08-19 11:25:19 -07002305void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2306 SkScalar sweepAngle, bool useCenter,
2307 const SkPaint& paint) {
2308 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2309 const SkRect* bounds = nullptr;
2310 if (paint.canComputeFastBounds()) {
2311 SkRect storage;
2312 // Note we're using the entire oval as the bounds.
2313 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2314 return;
2315 }
2316 bounds = &oval;
2317 }
2318
2319 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2320
2321 while (iter.next()) {
2322 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2323 }
2324
2325 LOOPER_END
2326}
2327
reed41af9662015-01-05 07:49:08 -08002328void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002329 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002330 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002331 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002332 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002333 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2334 return;
2335 }
2336 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002337 }
2338
2339 if (rrect.isRect()) {
2340 // call the non-virtual version
2341 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002342 return;
2343 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002344 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002345 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2346 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002347 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002348
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002349 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002350
2351 while (iter.next()) {
2352 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2353 }
2354
2355 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002356}
2357
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002358void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2359 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002360 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002361 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002362 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002363 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2364 return;
2365 }
2366 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002367 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002368
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002369 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002370
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002371 while (iter.next()) {
2372 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2373 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002374
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002375 LOOPER_END
2376}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002377
reed41af9662015-01-05 07:49:08 -08002378void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002379 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002380 if (!path.isFinite()) {
2381 return;
2382 }
2383
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002384 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002385 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002386 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002387 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002388 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2389 return;
2390 }
2391 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002392 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002393
2394 const SkRect& r = path.getBounds();
2395 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002396 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002397 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002398 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002399 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002400 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002401
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002402 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002403
2404 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002405 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002406 }
2407
reed@google.com4e2b3d32011-04-07 14:18:59 +00002408 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002409}
2410
reed262a71b2015-12-05 13:07:27 -08002411bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002412 if (!paint.getImageFilter()) {
2413 return false;
2414 }
2415
2416 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002417 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002418 return false;
2419 }
2420
2421 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2422 // Once we can filter and the filter will return a result larger than itself, we should be
2423 // able to remove this constraint.
2424 // skbug.com/4526
2425 //
2426 SkPoint pt;
2427 ctm.mapXY(x, y, &pt);
2428 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2429 return ir.contains(fMCRec->fRasterClip.getBounds());
2430}
2431
reeda85d4d02015-05-06 12:56:48 -07002432void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002433 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002434 SkRect bounds = SkRect::MakeXYWH(x, y,
2435 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002436 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002437 SkRect tmp = bounds;
2438 if (paint) {
2439 paint->computeFastBounds(tmp, &tmp);
2440 }
2441 if (this->quickReject(tmp)) {
2442 return;
2443 }
reeda85d4d02015-05-06 12:56:48 -07002444 }
halcanary9d524f22016-03-29 09:03:52 -07002445
reeda85d4d02015-05-06 12:56:48 -07002446 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002447 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002448 paint = lazy.init();
2449 }
reed262a71b2015-12-05 13:07:27 -08002450
reeda2217ef2016-07-20 06:04:34 -07002451 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002452 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2453 *paint);
2454 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002455 special = this->getDevice()->makeSpecial(image);
2456 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002457 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002458 }
2459 }
2460
reed262a71b2015-12-05 13:07:27 -08002461 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2462
reeda85d4d02015-05-06 12:56:48 -07002463 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002464 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002465 if (special) {
2466 SkPoint pt;
2467 iter.fMatrix->mapXY(x, y, &pt);
2468 iter.fDevice->drawSpecial(iter, special.get(),
2469 SkScalarRoundToInt(pt.fX),
2470 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002471 } else {
2472 iter.fDevice->drawImage(iter, image, x, y, pnt);
2473 }
reeda85d4d02015-05-06 12:56:48 -07002474 }
halcanary9d524f22016-03-29 09:03:52 -07002475
reeda85d4d02015-05-06 12:56:48 -07002476 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002477}
2478
reed41af9662015-01-05 07:49:08 -08002479void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002480 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002481 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002482 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002483 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002484 if (paint) {
2485 paint->computeFastBounds(dst, &storage);
2486 }
2487 if (this->quickReject(storage)) {
2488 return;
2489 }
reeda85d4d02015-05-06 12:56:48 -07002490 }
2491 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002492 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002493 paint = lazy.init();
2494 }
halcanary9d524f22016-03-29 09:03:52 -07002495
senorblancoc41e7e12015-12-07 12:51:30 -08002496 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002497 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002498
reeda85d4d02015-05-06 12:56:48 -07002499 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002500 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002501 }
halcanary9d524f22016-03-29 09:03:52 -07002502
reeda85d4d02015-05-06 12:56:48 -07002503 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002504}
2505
reed41af9662015-01-05 07:49:08 -08002506void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002507 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002508 SkDEBUGCODE(bitmap.validate();)
2509
reed33366972015-10-08 09:22:02 -07002510 if (bitmap.drawsNothing()) {
2511 return;
2512 }
2513
2514 SkLazyPaint lazy;
2515 if (nullptr == paint) {
2516 paint = lazy.init();
2517 }
2518
2519 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2520
2521 SkRect storage;
2522 const SkRect* bounds = nullptr;
2523 if (paint->canComputeFastBounds()) {
2524 bitmap.getBounds(&storage);
2525 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002526 SkRect tmp = storage;
2527 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2528 return;
2529 }
2530 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002531 }
reed@google.com4b226022011-01-11 18:32:13 +00002532
reeda2217ef2016-07-20 06:04:34 -07002533 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002534 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2535 *paint);
2536 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002537 special = this->getDevice()->makeSpecial(bitmap);
2538 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002539 drawAsSprite = false;
2540 }
2541 }
2542
reed262a71b2015-12-05 13:07:27 -08002543 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002544
2545 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002546 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002547 if (special) {
reed262a71b2015-12-05 13:07:27 -08002548 SkPoint pt;
2549 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002550 iter.fDevice->drawSpecial(iter, special.get(),
2551 SkScalarRoundToInt(pt.fX),
2552 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002553 } else {
2554 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2555 }
reed33366972015-10-08 09:22:02 -07002556 }
msarettfbfa2582016-08-12 08:29:08 -07002557
reed33366972015-10-08 09:22:02 -07002558 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002559}
2560
reed@google.com9987ec32011-09-07 11:57:52 +00002561// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002562void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002563 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002564 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002565 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002566 return;
2567 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002568
halcanary96fcdcc2015-08-27 07:41:13 -07002569 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002570 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002571 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2572 return;
2573 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002574 }
reed@google.com3d608122011-11-21 15:16:16 +00002575
reed@google.com33535f32012-09-25 15:37:50 +00002576 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002577 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002578 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002579 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002580
senorblancoc41e7e12015-12-07 12:51:30 -08002581 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002582 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002583
reed@google.com33535f32012-09-25 15:37:50 +00002584 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002585 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002586 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002587
reed@google.com33535f32012-09-25 15:37:50 +00002588 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002589}
2590
reed41af9662015-01-05 07:49:08 -08002591void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002592 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002593 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002594 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002595 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002596}
2597
reed4c21dc52015-06-25 12:32:03 -07002598void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2599 const SkPaint* paint) {
2600 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002601
halcanary96fcdcc2015-08-27 07:41:13 -07002602 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002603 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002604 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2605 return;
2606 }
reed@google.com3d608122011-11-21 15:16:16 +00002607 }
halcanary9d524f22016-03-29 09:03:52 -07002608
reed4c21dc52015-06-25 12:32:03 -07002609 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002610 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002611 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002612 }
halcanary9d524f22016-03-29 09:03:52 -07002613
senorblancoc41e7e12015-12-07 12:51:30 -08002614 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002615
reed4c21dc52015-06-25 12:32:03 -07002616 while (iter.next()) {
2617 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002618 }
halcanary9d524f22016-03-29 09:03:52 -07002619
reed4c21dc52015-06-25 12:32:03 -07002620 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002621}
2622
reed41af9662015-01-05 07:49:08 -08002623void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2624 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002625 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002626 SkDEBUGCODE(bitmap.validate();)
2627
halcanary96fcdcc2015-08-27 07:41:13 -07002628 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002629 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002630 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2631 return;
2632 }
reed4c21dc52015-06-25 12:32:03 -07002633 }
halcanary9d524f22016-03-29 09:03:52 -07002634
reed4c21dc52015-06-25 12:32:03 -07002635 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002636 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002637 paint = lazy.init();
2638 }
halcanary9d524f22016-03-29 09:03:52 -07002639
senorblancoc41e7e12015-12-07 12:51:30 -08002640 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002641
reed4c21dc52015-06-25 12:32:03 -07002642 while (iter.next()) {
2643 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2644 }
halcanary9d524f22016-03-29 09:03:52 -07002645
reed4c21dc52015-06-25 12:32:03 -07002646 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002647}
2648
msarett16882062016-08-16 09:31:08 -07002649void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2650 const SkPaint* paint) {
2651 if (nullptr == paint || paint->canComputeFastBounds()) {
2652 SkRect storage;
2653 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2654 return;
2655 }
2656 }
2657
2658 SkLazyPaint lazy;
2659 if (nullptr == paint) {
2660 paint = lazy.init();
2661 }
2662
2663 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2664
2665 while (iter.next()) {
2666 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2667 }
2668
2669 LOOPER_END
2670}
2671
2672void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2673 const SkRect& dst, const SkPaint* paint) {
2674 if (nullptr == paint || paint->canComputeFastBounds()) {
2675 SkRect storage;
2676 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2677 return;
2678 }
2679 }
2680
2681 SkLazyPaint lazy;
2682 if (nullptr == paint) {
2683 paint = lazy.init();
2684 }
2685
2686 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2687
2688 while (iter.next()) {
2689 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2690 }
2691
2692 LOOPER_END
2693}
2694
reed@google.comf67e4cf2011-03-15 20:56:58 +00002695class SkDeviceFilteredPaint {
2696public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002697 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002698 uint32_t filteredFlags = device->filterTextFlags(paint);
2699 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002700 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002701 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002702 fPaint = newPaint;
2703 } else {
2704 fPaint = &paint;
2705 }
2706 }
2707
reed@google.comf67e4cf2011-03-15 20:56:58 +00002708 const SkPaint& paint() const { return *fPaint; }
2709
2710private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002711 const SkPaint* fPaint;
2712 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002713};
2714
bungeman@google.com52c748b2011-08-22 21:30:43 +00002715void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2716 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002717 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002718 draw.fDevice->drawRect(draw, r, paint);
2719 } else {
2720 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002721 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002722 draw.fDevice->drawRect(draw, r, p);
2723 }
2724}
2725
2726void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2727 const char text[], size_t byteLength,
2728 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002729 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002730
2731 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002732 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002733 draw.fRC->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002734 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002735 return;
2736 }
2737
2738 SkScalar width = 0;
2739 SkPoint start;
2740
2741 start.set(0, 0); // to avoid warning
2742 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2743 SkPaint::kStrikeThruText_Flag)) {
2744 width = paint.measureText(text, byteLength);
2745
2746 SkScalar offsetX = 0;
2747 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2748 offsetX = SkScalarHalf(width);
2749 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2750 offsetX = width;
2751 }
2752 start.set(x - offsetX, y);
2753 }
2754
2755 if (0 == width) {
2756 return;
2757 }
2758
2759 uint32_t flags = paint.getFlags();
2760
2761 if (flags & (SkPaint::kUnderlineText_Flag |
2762 SkPaint::kStrikeThruText_Flag)) {
2763 SkScalar textSize = paint.getTextSize();
2764 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2765 SkRect r;
2766
2767 r.fLeft = start.fX;
2768 r.fRight = start.fX + width;
2769
2770 if (flags & SkPaint::kUnderlineText_Flag) {
2771 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2772 start.fY);
2773 r.fTop = offset;
2774 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002775 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002776 }
2777 if (flags & SkPaint::kStrikeThruText_Flag) {
2778 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2779 start.fY);
2780 r.fTop = offset;
2781 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002782 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002783 }
2784 }
2785}
2786
reed@google.come0d9ce82014-04-23 04:00:17 +00002787void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2788 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002789 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790
2791 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002792 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002793 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002794 DrawTextDecorations(iter, dfp.paint(),
2795 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796 }
2797
reed@google.com4e2b3d32011-04-07 14:18:59 +00002798 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002799}
2800
reed@google.come0d9ce82014-04-23 04:00:17 +00002801void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2802 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002803 SkPoint textOffset = SkPoint::Make(0, 0);
2804
halcanary96fcdcc2015-08-27 07:41:13 -07002805 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002806
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002808 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002809 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002810 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002811 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002812
reed@google.com4e2b3d32011-04-07 14:18:59 +00002813 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814}
2815
reed@google.come0d9ce82014-04-23 04:00:17 +00002816void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2817 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002818
2819 SkPoint textOffset = SkPoint::Make(0, constY);
2820
halcanary96fcdcc2015-08-27 07:41:13 -07002821 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002822
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002824 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002825 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002826 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002827 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002828
reed@google.com4e2b3d32011-04-07 14:18:59 +00002829 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002830}
2831
reed@google.come0d9ce82014-04-23 04:00:17 +00002832void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2833 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002834 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002835
reed@android.com8a1c16f2008-12-17 15:59:43 +00002836 while (iter.next()) {
2837 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002838 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002839 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002840
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002841 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002842}
2843
reed45561a02016-07-07 12:47:17 -07002844void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2845 const SkRect* cullRect, const SkPaint& paint) {
2846 if (cullRect && this->quickReject(*cullRect)) {
2847 return;
2848 }
2849
2850 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2851
2852 while (iter.next()) {
2853 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2854 }
2855
2856 LOOPER_END
2857}
2858
fmalita00d5c2c2014-08-21 08:53:26 -07002859void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2860 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002861
fmalita85d5eb92015-03-04 11:20:12 -08002862 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002863 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002864 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002865 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002866 SkRect tmp;
2867 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2868 return;
2869 }
2870 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002871 }
2872
fmalita024f9962015-03-03 19:08:17 -08002873 // We cannot filter in the looper as we normally do, because the paint is
2874 // incomplete at this point (text-related attributes are embedded within blob run paints).
2875 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002876 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002877
fmalita85d5eb92015-03-04 11:20:12 -08002878 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002879
fmalitaaa1b9122014-08-28 14:32:24 -07002880 while (iter.next()) {
2881 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002882 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002883 }
2884
fmalitaaa1b9122014-08-28 14:32:24 -07002885 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002886
2887 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002888}
2889
reed@google.come0d9ce82014-04-23 04:00:17 +00002890// These will become non-virtual, so they always call the (virtual) onDraw... method
2891void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2892 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002893 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002894 if (byteLength) {
2895 this->onDrawText(text, byteLength, x, y, paint);
2896 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002897}
2898void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2899 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002900 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002901 if (byteLength) {
2902 this->onDrawPosText(text, byteLength, pos, paint);
2903 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002904}
2905void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2906 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002907 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002908 if (byteLength) {
2909 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2910 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002911}
2912void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2913 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002914 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002915 if (byteLength) {
2916 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2917 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002918}
reed45561a02016-07-07 12:47:17 -07002919void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2920 const SkRect* cullRect, const SkPaint& paint) {
2921 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2922 if (byteLength) {
2923 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2924 }
2925}
fmalita00d5c2c2014-08-21 08:53:26 -07002926void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2927 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002928 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002929 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002930 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002931}
reed@google.come0d9ce82014-04-23 04:00:17 +00002932
reed41af9662015-01-05 07:49:08 -08002933void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2934 const SkPoint verts[], const SkPoint texs[],
2935 const SkColor colors[], SkXfermode* xmode,
2936 const uint16_t indices[], int indexCount,
2937 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002938 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002939 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002940
reed@android.com8a1c16f2008-12-17 15:59:43 +00002941 while (iter.next()) {
2942 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002943 colors, xmode, indices, indexCount,
2944 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002945 }
reed@google.com4b226022011-01-11 18:32:13 +00002946
reed@google.com4e2b3d32011-04-07 14:18:59 +00002947 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002948}
2949
dandovb3c9d1c2014-08-12 08:34:29 -07002950void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2951 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002952 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002953 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002954 return;
2955 }
mtklein6cfa73a2014-08-13 13:33:49 -07002956
dandovecfff212014-08-04 10:02:00 -07002957 // Since a patch is always within the convex hull of the control points, we discard it when its
2958 // bounding rectangle is completely outside the current clip.
2959 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002960 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002961 if (this->quickReject(bounds)) {
2962 return;
2963 }
mtklein6cfa73a2014-08-13 13:33:49 -07002964
dandovb3c9d1c2014-08-12 08:34:29 -07002965 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2966}
2967
2968void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2969 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2970
halcanary96fcdcc2015-08-27 07:41:13 -07002971 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002972
dandovecfff212014-08-04 10:02:00 -07002973 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002974 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002975 }
mtklein6cfa73a2014-08-13 13:33:49 -07002976
dandovecfff212014-08-04 10:02:00 -07002977 LOOPER_END
2978}
2979
reeda8db7282015-07-07 10:22:31 -07002980void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002981 RETURN_ON_NULL(dr);
2982 if (x || y) {
2983 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2984 this->onDrawDrawable(dr, &matrix);
2985 } else {
2986 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002987 }
2988}
2989
reeda8db7282015-07-07 10:22:31 -07002990void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002991 RETURN_ON_NULL(dr);
2992 if (matrix && matrix->isIdentity()) {
2993 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002994 }
reede3b38ce2016-01-08 09:18:44 -08002995 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002996}
2997
2998void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2999 SkRect bounds = dr->getBounds();
3000 if (matrix) {
3001 matrix->mapRect(&bounds);
3002 }
3003 if (this->quickReject(bounds)) {
3004 return;
3005 }
3006 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08003007}
3008
reed71c3c762015-06-24 10:29:17 -07003009void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
3010 const SkColor colors[], int count, SkXfermode::Mode mode,
3011 const SkRect* cull, const SkPaint* paint) {
3012 if (cull && this->quickReject(*cull)) {
3013 return;
3014 }
3015
3016 SkPaint pnt;
3017 if (paint) {
3018 pnt = *paint;
3019 }
halcanary9d524f22016-03-29 09:03:52 -07003020
halcanary96fcdcc2015-08-27 07:41:13 -07003021 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07003022 while (iter.next()) {
3023 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
3024 }
3025 LOOPER_END
3026}
3027
reedf70b5312016-03-04 16:36:20 -08003028void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
3029 SkASSERT(key);
3030
3031 SkPaint paint;
3032 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
3033 while (iter.next()) {
3034 iter.fDevice->drawAnnotation(iter, rect, key, value);
3035 }
3036 LOOPER_END
3037}
3038
reed@android.com8a1c16f2008-12-17 15:59:43 +00003039//////////////////////////////////////////////////////////////////////////////
3040// These methods are NOT virtual, and therefore must call back into virtual
3041// methods, rather than actually drawing themselves.
3042//////////////////////////////////////////////////////////////////////////////
3043
3044void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00003045 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003046 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003047 SkPaint paint;
3048
3049 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00003050 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003051 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003052 }
3053 this->drawPaint(paint);
3054}
3055
reed@android.com845fdac2009-06-23 03:01:32 +00003056void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003057 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003058 SkPaint paint;
3059
3060 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00003061 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003062 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003063 }
3064 this->drawPaint(paint);
3065}
3066
3067void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003068 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003069 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00003070
reed@android.com8a1c16f2008-12-17 15:59:43 +00003071 pt.set(x, y);
3072 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3073}
3074
3075void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08003076 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003077 SkPoint pt;
3078 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00003079
reed@android.com8a1c16f2008-12-17 15:59:43 +00003080 pt.set(x, y);
3081 paint.setColor(color);
3082 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3083}
3084
3085void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
3086 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003087 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003088 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003089
reed@android.com8a1c16f2008-12-17 15:59:43 +00003090 pts[0].set(x0, y0);
3091 pts[1].set(x1, y1);
3092 this->drawPoints(kLines_PointMode, 2, pts, paint);
3093}
3094
3095void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3096 SkScalar right, SkScalar bottom,
3097 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003098 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003099 SkRect r;
3100
3101 r.set(left, top, right, bottom);
3102 this->drawRect(r, paint);
3103}
3104
3105void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3106 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003107 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003108 if (radius < 0) {
3109 radius = 0;
3110 }
3111
3112 SkRect r;
3113 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003114 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003115}
3116
3117void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3118 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003119 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003120 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003121 SkRRect rrect;
3122 rrect.setRectXY(r, rx, ry);
3123 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003124 } else {
3125 this->drawRect(r, paint);
3126 }
3127}
3128
reed@android.com8a1c16f2008-12-17 15:59:43 +00003129void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3130 SkScalar sweepAngle, bool useCenter,
3131 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003132 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003133 if (oval.isEmpty() || !sweepAngle) {
3134 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003135 }
bsalomon21af9ca2016-08-25 12:29:23 -07003136 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003137}
3138
3139void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3140 const SkPath& path, SkScalar hOffset,
3141 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003142 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003143 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003144
reed@android.com8a1c16f2008-12-17 15:59:43 +00003145 matrix.setTranslate(hOffset, vOffset);
3146 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3147}
3148
reed@android.comf76bacf2009-05-13 14:00:33 +00003149///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003150
3151/**
3152 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3153 * against the playback cost of recursing into the subpicture to get at its actual ops.
3154 *
3155 * For now we pick a conservatively small value, though measurement (and other heuristics like
3156 * the type of ops contained) may justify changing this value.
3157 */
3158#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003159
reedd5fa1a42014-08-09 11:08:05 -07003160void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003161 RETURN_ON_NULL(picture);
3162
reed1c2c4412015-04-30 13:09:24 -07003163 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003164 if (matrix && matrix->isIdentity()) {
3165 matrix = nullptr;
3166 }
3167 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3168 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3169 picture->playback(this);
3170 } else {
3171 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003172 }
3173}
robertphillips9b14f262014-06-04 05:40:44 -07003174
reedd5fa1a42014-08-09 11:08:05 -07003175void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3176 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003177 if (!paint || paint->canComputeFastBounds()) {
3178 SkRect bounds = picture->cullRect();
3179 if (paint) {
3180 paint->computeFastBounds(bounds, &bounds);
3181 }
3182 if (matrix) {
3183 matrix->mapRect(&bounds);
3184 }
3185 if (this->quickReject(bounds)) {
3186 return;
3187 }
3188 }
3189
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003190 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003191 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003192}
3193
vjiaoblack95302da2016-07-21 10:25:54 -07003194#ifdef SK_EXPERIMENTAL_SHADOWING
3195void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3196 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003197 const SkPaint* paint,
3198 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003199 RETURN_ON_NULL(picture);
3200
3201 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3202
vjiaoblacke6f5d562016-08-25 06:30:23 -07003203 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003204}
3205
3206void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3207 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003208 const SkPaint* paint,
3209 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003210 if (!paint || paint->canComputeFastBounds()) {
3211 SkRect bounds = picture->cullRect();
3212 if (paint) {
3213 paint->computeFastBounds(bounds, &bounds);
3214 }
3215 if (matrix) {
3216 matrix->mapRect(&bounds);
3217 }
3218 if (this->quickReject(bounds)) {
3219 return;
3220 }
3221 }
3222
3223 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3224
vjiaoblacke6f5d562016-08-25 06:30:23 -07003225 sk_sp<SkImage> povDepthMap;
3226 sk_sp<SkImage> diffuseMap;
3227
3228 // TODO: pass the depth to the shader in vertices, or uniforms
3229 // so we don't have to render depth and color separately
vjiaoblack904527d2016-08-09 09:32:09 -07003230 for (int i = 0; i < fLights->numLights(); ++i) {
3231 // skip over ambient lights; they don't cast shadows
3232 // lights that have shadow maps do not need updating (because lights are immutable)
3233
3234 if (SkLights::Light::kAmbient_LightType == fLights->light(i).type() ||
3235 fLights->light(i).getShadowMap() != nullptr) {
3236 continue;
3237 }
3238
3239 // TODO: compute the correct size of the depth map from the light properties
3240 // TODO: maybe add a kDepth_8_SkColorType
3241 // TODO: find actual max depth of picture
3242 SkISize shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3243 fLights->light(i), 255,
3244 picture->cullRect().width(),
3245 picture->cullRect().height());
3246
3247 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3248 kBGRA_8888_SkColorType,
3249 kOpaque_SkAlphaType);
3250
3251 // Create a new surface (that matches the backend of canvas)
3252 // for each shadow map
3253 sk_sp<SkSurface> surf(this->makeSurface(info));
3254
3255 // Wrap another SPFCanvas around the surface
3256 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3257 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
vjiaoblacke6f5d562016-08-25 06:30:23 -07003258 depthMapCanvas->setShadowParams(params);
vjiaoblack904527d2016-08-09 09:32:09 -07003259
3260 // set the depth map canvas to have the light we're drawing.
3261 SkLights::Builder builder;
3262 builder.add(fLights->light(i));
3263 sk_sp<SkLights> curLight = builder.finish();
vjiaoblack904527d2016-08-09 09:32:09 -07003264 depthMapCanvas->setLights(std::move(curLight));
vjiaoblacke6f5d562016-08-25 06:30:23 -07003265
vjiaoblack904527d2016-08-09 09:32:09 -07003266 depthMapCanvas->drawPicture(picture);
vjiaoblacke6f5d562016-08-25 06:30:23 -07003267 sk_sp<SkImage> depthMap = surf->makeImageSnapshot();
vjiaoblack904527d2016-08-09 09:32:09 -07003268
vjiaoblacke6f5d562016-08-25 06:30:23 -07003269 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3270 fLights->light(i).setShadowMap(std::move(depthMap));
3271 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3272 // we blur the variance map
3273 SkPaint blurPaint;
3274 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3275 params.fShadowRadius, nullptr));
3276
3277 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3278 kBGRA_8888_SkColorType,
3279 kOpaque_SkAlphaType);
3280
3281 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3282
3283 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3284
3285 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3286 }
vjiaoblack904527d2016-08-09 09:32:09 -07003287 }
3288
vjiaoblack904527d2016-08-09 09:32:09 -07003289 // povDepthMap
3290 {
3291 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003292 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3293 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003294 sk_sp<SkLights> povLight = builder.finish();
3295
3296 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3297 picture->cullRect().height(),
3298 kBGRA_8888_SkColorType,
3299 kOpaque_SkAlphaType);
3300
3301 // Create a new surface (that matches the backend of canvas)
3302 // to create the povDepthMap
3303 sk_sp<SkSurface> surf(this->makeSurface(info));
3304
3305 // Wrap another SPFCanvas around the surface
3306 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3307 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3308
3309 // set the depth map canvas to have the light as the user's POV
3310 depthMapCanvas->setLights(std::move(povLight));
3311
3312 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003313 povDepthMap = surf->makeImageSnapshot();
3314 }
3315
3316 // diffuseMap
3317 {
3318 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3319 picture->cullRect().height(),
3320 kBGRA_8888_SkColorType,
3321 kOpaque_SkAlphaType);
3322
3323 sk_sp<SkSurface> surf(this->makeSurface(info));
3324 surf->getCanvas()->drawPicture(picture);
3325
3326 diffuseMap = surf->makeImageSnapshot();
3327 }
vjiaoblack904527d2016-08-09 09:32:09 -07003328 SkPaint shadowPaint;
3329
3330 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3331 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003332 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3333 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003334 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3335 std::move(diffuseShader),
3336 std::move(fLights),
3337 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003338 diffuseMap->height(),
3339 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003340
3341 shadowPaint.setShader(shadowShader);
3342
3343 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003344}
3345#endif
3346
reed@android.com8a1c16f2008-12-17 15:59:43 +00003347///////////////////////////////////////////////////////////////////////////////
3348///////////////////////////////////////////////////////////////////////////////
3349
reed3aafe112016-08-18 12:45:34 -07003350SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003351 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003352
3353 SkASSERT(canvas);
3354
reed3aafe112016-08-18 12:45:34 -07003355 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003356 fDone = !fImpl->next();
3357}
3358
3359SkCanvas::LayerIter::~LayerIter() {
3360 fImpl->~SkDrawIter();
3361}
3362
3363void SkCanvas::LayerIter::next() {
3364 fDone = !fImpl->next();
3365}
3366
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003367SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003368 return fImpl->getDevice();
3369}
3370
3371const SkMatrix& SkCanvas::LayerIter::matrix() const {
3372 return fImpl->getMatrix();
3373}
3374
3375const SkPaint& SkCanvas::LayerIter::paint() const {
3376 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003377 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003378 paint = &fDefaultPaint;
3379 }
3380 return *paint;
3381}
3382
reed1e7f5e72016-04-27 07:49:17 -07003383const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003384int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3385int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003386
3387///////////////////////////////////////////////////////////////////////////////
3388
fmalitac3b589a2014-06-05 12:40:07 -07003389SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003390
3391///////////////////////////////////////////////////////////////////////////////
3392
3393static bool supported_for_raster_canvas(const SkImageInfo& info) {
3394 switch (info.alphaType()) {
3395 case kPremul_SkAlphaType:
3396 case kOpaque_SkAlphaType:
3397 break;
3398 default:
3399 return false;
3400 }
3401
3402 switch (info.colorType()) {
3403 case kAlpha_8_SkColorType:
3404 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003405 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003406 break;
3407 default:
3408 return false;
3409 }
3410
3411 return true;
3412}
3413
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003414SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3415 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003416 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003417 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003418
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003419 SkBitmap bitmap;
3420 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003421 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003422 }
halcanary385fe4d2015-08-26 13:07:48 -07003423 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003424}
reedd5fa1a42014-08-09 11:08:05 -07003425
3426///////////////////////////////////////////////////////////////////////////////
3427
3428SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003429 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003430 : fCanvas(canvas)
3431 , fSaveCount(canvas->getSaveCount())
3432{
bsalomon49f085d2014-09-05 13:34:00 -07003433 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003434 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003435 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003436 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003437 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003438 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003439 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003440 canvas->save();
3441 }
mtklein6cfa73a2014-08-13 13:33:49 -07003442
bsalomon49f085d2014-09-05 13:34:00 -07003443 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003444 canvas->concat(*matrix);
3445 }
3446}
3447
3448SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3449 fCanvas->restoreToCount(fSaveCount);
3450}
reede8f30622016-03-23 18:59:25 -07003451
3452#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3453SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
3454 return this->makeSurface(info, props).release();
3455}
3456#endif