blob: 4cf40e9c5a9afbf48e022043deca55ea7f8977c1 [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
1978void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1979 this->onDrawOval(r, paint);
1980}
1981
1982void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1983 this->onDrawRRect(rrect, paint);
1984}
1985
1986void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1987 this->onDrawPoints(mode, count, pts, paint);
1988}
1989
1990void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1991 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1992 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1993 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1994 indices, indexCount, paint);
1995}
1996
1997void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1998 this->onDrawPath(path, paint);
1999}
2000
reeda85d4d02015-05-06 12:56:48 -07002001void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002002 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07002003 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08002004}
2005
reede47829b2015-08-06 10:02:53 -07002006void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
2007 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002008 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002009 if (dst.isEmpty() || src.isEmpty()) {
2010 return;
2011 }
2012 this->onDrawImageRect(image, &src, dst, paint, constraint);
2013}
reed41af9662015-01-05 07:49:08 -08002014
reed84984ef2015-07-17 07:09:43 -07002015void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
2016 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002017 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002018 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002019}
2020
reede47829b2015-08-06 10:02:53 -07002021void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
2022 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002023 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002024 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
2025 constraint);
2026}
reede47829b2015-08-06 10:02:53 -07002027
reed4c21dc52015-06-25 12:32:03 -07002028void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2029 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002030 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07002031 if (dst.isEmpty()) {
2032 return;
2033 }
msarett552bca92016-08-03 06:53:26 -07002034 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
2035 this->onDrawImageNine(image, center, dst, paint);
2036 } else {
reede47829b2015-08-06 10:02:53 -07002037 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002038 }
reed4c21dc52015-06-25 12:32:03 -07002039}
2040
msarett16882062016-08-16 09:31:08 -07002041void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2042 const SkPaint* paint) {
2043 RETURN_ON_NULL(image);
2044 if (dst.isEmpty()) {
2045 return;
2046 }
2047 if (SkLatticeIter::Valid(image->width(), image->height(), lattice)) {
2048 this->onDrawImageLattice(image, lattice, dst, paint);
2049 } else {
2050 this->drawImageRect(image, dst, paint);
2051 }
2052}
2053
reed41af9662015-01-05 07:49:08 -08002054void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002055 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002056 return;
2057 }
reed41af9662015-01-05 07:49:08 -08002058 this->onDrawBitmap(bitmap, dx, dy, paint);
2059}
2060
reede47829b2015-08-06 10:02:53 -07002061void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002062 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002063 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002064 return;
2065 }
reede47829b2015-08-06 10:02:53 -07002066 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002067}
2068
reed84984ef2015-07-17 07:09:43 -07002069void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2070 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002071 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002072}
2073
reede47829b2015-08-06 10:02:53 -07002074void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2075 SrcRectConstraint constraint) {
2076 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2077 constraint);
2078}
reede47829b2015-08-06 10:02:53 -07002079
reed41af9662015-01-05 07:49:08 -08002080void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2081 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002082 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002083 return;
2084 }
msarett552bca92016-08-03 06:53:26 -07002085 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2086 this->onDrawBitmapNine(bitmap, center, dst, paint);
2087 } else {
reeda5517e22015-07-14 10:54:12 -07002088 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002089 }
reed41af9662015-01-05 07:49:08 -08002090}
2091
msarettc573a402016-08-02 08:05:56 -07002092void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2093 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002094 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002095 return;
2096 }
msarett16882062016-08-16 09:31:08 -07002097 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), lattice)) {
2098 this->onDrawBitmapLattice(bitmap, lattice, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002099 } else {
msarett16882062016-08-16 09:31:08 -07002100 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002101 }
msarettc573a402016-08-02 08:05:56 -07002102}
2103
reed71c3c762015-06-24 10:29:17 -07002104void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2105 const SkColor colors[], int count, SkXfermode::Mode mode,
2106 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002107 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002108 if (count <= 0) {
2109 return;
2110 }
2111 SkASSERT(atlas);
2112 SkASSERT(xform);
2113 SkASSERT(tex);
2114 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2115}
2116
reedf70b5312016-03-04 16:36:20 -08002117void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2118 if (key) {
2119 this->onDrawAnnotation(rect, key, value);
2120 }
2121}
2122
reede47829b2015-08-06 10:02:53 -07002123void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2124 const SkPaint* paint, SrcRectConstraint constraint) {
2125 if (src) {
2126 this->drawImageRect(image, *src, dst, paint, constraint);
2127 } else {
2128 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2129 dst, paint, constraint);
2130 }
2131}
2132void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2133 const SkPaint* paint, SrcRectConstraint constraint) {
2134 if (src) {
2135 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2136 } else {
2137 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2138 dst, paint, constraint);
2139 }
2140}
2141
tomhudsoncb3bd182016-05-18 07:24:16 -07002142void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2143 SkIRect layer_bounds = this->getTopLayerBounds();
2144 if (matrix) {
2145 *matrix = this->getTotalMatrix();
2146 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2147 }
2148 if (clip_bounds) {
2149 this->getClipDeviceBounds(clip_bounds);
2150 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2151 }
2152}
2153
reed@android.com8a1c16f2008-12-17 15:59:43 +00002154//////////////////////////////////////////////////////////////////////////////
2155// These are the virtual drawing methods
2156//////////////////////////////////////////////////////////////////////////////
2157
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002158void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002159 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002160 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2161 }
2162}
2163
reed41af9662015-01-05 07:49:08 -08002164void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002165 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002166 this->internalDrawPaint(paint);
2167}
2168
2169void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002170 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002171
2172 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002173 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002174 }
2175
reed@google.com4e2b3d32011-04-07 14:18:59 +00002176 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002177}
2178
reed41af9662015-01-05 07:49:08 -08002179void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2180 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002181 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002182 if ((long)count <= 0) {
2183 return;
2184 }
2185
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002186 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002187 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002188 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002189 // special-case 2 points (common for drawing a single line)
2190 if (2 == count) {
2191 r.set(pts[0], pts[1]);
2192 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002193 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002194 }
senorblanco87e066e2015-10-28 11:23:36 -07002195 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2196 return;
2197 }
2198 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002199 }
reed@google.coma584aed2012-05-16 14:06:02 +00002200
halcanary96fcdcc2015-08-27 07:41:13 -07002201 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002202
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002203 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002204
reed@android.com8a1c16f2008-12-17 15:59:43 +00002205 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002206 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002207 }
reed@google.com4b226022011-01-11 18:32:13 +00002208
reed@google.com4e2b3d32011-04-07 14:18:59 +00002209 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002210}
2211
reed4a167172016-08-18 17:15:25 -07002212static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2213 return ((intptr_t)paint.getImageFilter() |
2214#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2215 (intptr_t)canvas->getDrawFilter() |
2216#endif
2217 (intptr_t)paint.getLooper() ) != 0;
2218}
2219
reed41af9662015-01-05 07:49:08 -08002220void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002221 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002222 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002223 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002224 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002225 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2226 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2227 SkRect tmp(r);
2228 tmp.sort();
2229
senorblanco87e066e2015-10-28 11:23:36 -07002230 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2231 return;
2232 }
2233 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002234 }
reed@google.com4b226022011-01-11 18:32:13 +00002235
reed4a167172016-08-18 17:15:25 -07002236 if (needs_autodrawlooper(this, paint)) {
2237 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002238
reed4a167172016-08-18 17:15:25 -07002239 while (iter.next()) {
2240 iter.fDevice->drawRect(iter, r, looper.paint());
2241 }
2242
2243 LOOPER_END
2244 } else {
2245 this->predrawNotify(bounds, &paint, false);
2246 SkDrawIter iter(this);
2247 while (iter.next()) {
2248 iter.fDevice->drawRect(iter, r, paint);
2249 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002250 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002251}
2252
msarett44df6512016-08-25 13:54:30 -07002253void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2254 SkRect storage;
2255 SkRect regionRect = SkRect::Make(region.getBounds());
2256 const SkRect* bounds = nullptr;
2257 if (paint.canComputeFastBounds()) {
2258 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2259 return;
2260 }
2261 bounds = &regionRect;
2262 }
2263
2264 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2265
2266 while (iter.next()) {
2267 iter.fDevice->drawRegion(iter, region, looper.paint());
2268 }
2269
2270 LOOPER_END
2271}
2272
reed41af9662015-01-05 07:49:08 -08002273void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002274 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002275 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002276 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002277 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002278 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2279 return;
2280 }
2281 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002282 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002283
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002284 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002285
2286 while (iter.next()) {
2287 iter.fDevice->drawOval(iter, oval, looper.paint());
2288 }
2289
2290 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002291}
2292
bsalomonac3aa242016-08-19 11:25:19 -07002293void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2294 SkScalar sweepAngle, bool useCenter,
2295 const SkPaint& paint) {
2296 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2297 const SkRect* bounds = nullptr;
2298 if (paint.canComputeFastBounds()) {
2299 SkRect storage;
2300 // Note we're using the entire oval as the bounds.
2301 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2302 return;
2303 }
2304 bounds = &oval;
2305 }
2306
2307 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2308
2309 while (iter.next()) {
2310 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2311 }
2312
2313 LOOPER_END
2314}
2315
reed41af9662015-01-05 07:49:08 -08002316void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002317 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002318 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002319 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002320 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002321 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2322 return;
2323 }
2324 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002325 }
2326
2327 if (rrect.isRect()) {
2328 // call the non-virtual version
2329 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002330 return;
2331 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002332 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002333 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2334 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002335 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002336
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002337 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002338
2339 while (iter.next()) {
2340 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2341 }
2342
2343 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002344}
2345
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002346void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2347 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002348 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002349 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002350 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002351 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2352 return;
2353 }
2354 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002355 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002356
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002357 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002358
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002359 while (iter.next()) {
2360 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2361 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002362
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002363 LOOPER_END
2364}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002365
reed41af9662015-01-05 07:49:08 -08002366void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002367 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002368 if (!path.isFinite()) {
2369 return;
2370 }
2371
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002372 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002373 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002374 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002375 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002376 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2377 return;
2378 }
2379 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002380 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002381
2382 const SkRect& r = path.getBounds();
2383 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002384 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002385 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002386 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002387 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002388 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002389
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002390 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002391
2392 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002393 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002394 }
2395
reed@google.com4e2b3d32011-04-07 14:18:59 +00002396 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002397}
2398
reed262a71b2015-12-05 13:07:27 -08002399bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002400 if (!paint.getImageFilter()) {
2401 return false;
2402 }
2403
2404 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002405 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002406 return false;
2407 }
2408
2409 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2410 // Once we can filter and the filter will return a result larger than itself, we should be
2411 // able to remove this constraint.
2412 // skbug.com/4526
2413 //
2414 SkPoint pt;
2415 ctm.mapXY(x, y, &pt);
2416 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2417 return ir.contains(fMCRec->fRasterClip.getBounds());
2418}
2419
reeda85d4d02015-05-06 12:56:48 -07002420void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002421 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002422 SkRect bounds = SkRect::MakeXYWH(x, y,
2423 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002424 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002425 SkRect tmp = bounds;
2426 if (paint) {
2427 paint->computeFastBounds(tmp, &tmp);
2428 }
2429 if (this->quickReject(tmp)) {
2430 return;
2431 }
reeda85d4d02015-05-06 12:56:48 -07002432 }
halcanary9d524f22016-03-29 09:03:52 -07002433
reeda85d4d02015-05-06 12:56:48 -07002434 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002435 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002436 paint = lazy.init();
2437 }
reed262a71b2015-12-05 13:07:27 -08002438
reeda2217ef2016-07-20 06:04:34 -07002439 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002440 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2441 *paint);
2442 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002443 special = this->getDevice()->makeSpecial(image);
2444 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002445 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002446 }
2447 }
2448
reed262a71b2015-12-05 13:07:27 -08002449 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2450
reeda85d4d02015-05-06 12:56:48 -07002451 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002452 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002453 if (special) {
2454 SkPoint pt;
2455 iter.fMatrix->mapXY(x, y, &pt);
2456 iter.fDevice->drawSpecial(iter, special.get(),
2457 SkScalarRoundToInt(pt.fX),
2458 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002459 } else {
2460 iter.fDevice->drawImage(iter, image, x, y, pnt);
2461 }
reeda85d4d02015-05-06 12:56:48 -07002462 }
halcanary9d524f22016-03-29 09:03:52 -07002463
reeda85d4d02015-05-06 12:56:48 -07002464 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002465}
2466
reed41af9662015-01-05 07:49:08 -08002467void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002468 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002469 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002470 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002471 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002472 if (paint) {
2473 paint->computeFastBounds(dst, &storage);
2474 }
2475 if (this->quickReject(storage)) {
2476 return;
2477 }
reeda85d4d02015-05-06 12:56:48 -07002478 }
2479 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002480 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002481 paint = lazy.init();
2482 }
halcanary9d524f22016-03-29 09:03:52 -07002483
senorblancoc41e7e12015-12-07 12:51:30 -08002484 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002485 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002486
reeda85d4d02015-05-06 12:56:48 -07002487 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002488 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002489 }
halcanary9d524f22016-03-29 09:03:52 -07002490
reeda85d4d02015-05-06 12:56:48 -07002491 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002492}
2493
reed41af9662015-01-05 07:49:08 -08002494void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002495 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496 SkDEBUGCODE(bitmap.validate();)
2497
reed33366972015-10-08 09:22:02 -07002498 if (bitmap.drawsNothing()) {
2499 return;
2500 }
2501
2502 SkLazyPaint lazy;
2503 if (nullptr == paint) {
2504 paint = lazy.init();
2505 }
2506
2507 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2508
2509 SkRect storage;
2510 const SkRect* bounds = nullptr;
2511 if (paint->canComputeFastBounds()) {
2512 bitmap.getBounds(&storage);
2513 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002514 SkRect tmp = storage;
2515 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2516 return;
2517 }
2518 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002519 }
reed@google.com4b226022011-01-11 18:32:13 +00002520
reeda2217ef2016-07-20 06:04:34 -07002521 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002522 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2523 *paint);
2524 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002525 special = this->getDevice()->makeSpecial(bitmap);
2526 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002527 drawAsSprite = false;
2528 }
2529 }
2530
reed262a71b2015-12-05 13:07:27 -08002531 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002532
2533 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002534 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002535 if (special) {
reed262a71b2015-12-05 13:07:27 -08002536 SkPoint pt;
2537 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002538 iter.fDevice->drawSpecial(iter, special.get(),
2539 SkScalarRoundToInt(pt.fX),
2540 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002541 } else {
2542 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2543 }
reed33366972015-10-08 09:22:02 -07002544 }
msarettfbfa2582016-08-12 08:29:08 -07002545
reed33366972015-10-08 09:22:02 -07002546 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002547}
2548
reed@google.com9987ec32011-09-07 11:57:52 +00002549// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002550void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002551 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002552 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002553 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002554 return;
2555 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002556
halcanary96fcdcc2015-08-27 07:41:13 -07002557 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002558 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002559 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2560 return;
2561 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002562 }
reed@google.com3d608122011-11-21 15:16:16 +00002563
reed@google.com33535f32012-09-25 15:37:50 +00002564 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002565 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002566 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002567 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002568
senorblancoc41e7e12015-12-07 12:51:30 -08002569 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002570 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002571
reed@google.com33535f32012-09-25 15:37:50 +00002572 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002573 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002574 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002575
reed@google.com33535f32012-09-25 15:37:50 +00002576 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002577}
2578
reed41af9662015-01-05 07:49:08 -08002579void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002580 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002581 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002582 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002583 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002584}
2585
reed4c21dc52015-06-25 12:32:03 -07002586void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2587 const SkPaint* paint) {
2588 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002589
halcanary96fcdcc2015-08-27 07:41:13 -07002590 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002591 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002592 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2593 return;
2594 }
reed@google.com3d608122011-11-21 15:16:16 +00002595 }
halcanary9d524f22016-03-29 09:03:52 -07002596
reed4c21dc52015-06-25 12:32:03 -07002597 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002598 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002599 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002600 }
halcanary9d524f22016-03-29 09:03:52 -07002601
senorblancoc41e7e12015-12-07 12:51:30 -08002602 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002603
reed4c21dc52015-06-25 12:32:03 -07002604 while (iter.next()) {
2605 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002606 }
halcanary9d524f22016-03-29 09:03:52 -07002607
reed4c21dc52015-06-25 12:32:03 -07002608 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002609}
2610
reed41af9662015-01-05 07:49:08 -08002611void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2612 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002613 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002614 SkDEBUGCODE(bitmap.validate();)
2615
halcanary96fcdcc2015-08-27 07:41:13 -07002616 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002617 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002618 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2619 return;
2620 }
reed4c21dc52015-06-25 12:32:03 -07002621 }
halcanary9d524f22016-03-29 09:03:52 -07002622
reed4c21dc52015-06-25 12:32:03 -07002623 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002624 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002625 paint = lazy.init();
2626 }
halcanary9d524f22016-03-29 09:03:52 -07002627
senorblancoc41e7e12015-12-07 12:51:30 -08002628 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002629
reed4c21dc52015-06-25 12:32:03 -07002630 while (iter.next()) {
2631 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2632 }
halcanary9d524f22016-03-29 09:03:52 -07002633
reed4c21dc52015-06-25 12:32:03 -07002634 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002635}
2636
msarett16882062016-08-16 09:31:08 -07002637void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2638 const SkPaint* paint) {
2639 if (nullptr == paint || paint->canComputeFastBounds()) {
2640 SkRect storage;
2641 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2642 return;
2643 }
2644 }
2645
2646 SkLazyPaint lazy;
2647 if (nullptr == paint) {
2648 paint = lazy.init();
2649 }
2650
2651 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2652
2653 while (iter.next()) {
2654 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2655 }
2656
2657 LOOPER_END
2658}
2659
2660void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2661 const SkRect& dst, const SkPaint* paint) {
2662 if (nullptr == paint || paint->canComputeFastBounds()) {
2663 SkRect storage;
2664 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2665 return;
2666 }
2667 }
2668
2669 SkLazyPaint lazy;
2670 if (nullptr == paint) {
2671 paint = lazy.init();
2672 }
2673
2674 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2675
2676 while (iter.next()) {
2677 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2678 }
2679
2680 LOOPER_END
2681}
2682
reed@google.comf67e4cf2011-03-15 20:56:58 +00002683class SkDeviceFilteredPaint {
2684public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002685 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002686 uint32_t filteredFlags = device->filterTextFlags(paint);
2687 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002688 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002689 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002690 fPaint = newPaint;
2691 } else {
2692 fPaint = &paint;
2693 }
2694 }
2695
reed@google.comf67e4cf2011-03-15 20:56:58 +00002696 const SkPaint& paint() const { return *fPaint; }
2697
2698private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002699 const SkPaint* fPaint;
2700 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002701};
2702
bungeman@google.com52c748b2011-08-22 21:30:43 +00002703void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2704 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002705 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002706 draw.fDevice->drawRect(draw, r, paint);
2707 } else {
2708 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002709 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002710 draw.fDevice->drawRect(draw, r, p);
2711 }
2712}
2713
2714void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2715 const char text[], size_t byteLength,
2716 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002717 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002718
2719 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002720 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002721 draw.fRC->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002722 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002723 return;
2724 }
2725
2726 SkScalar width = 0;
2727 SkPoint start;
2728
2729 start.set(0, 0); // to avoid warning
2730 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2731 SkPaint::kStrikeThruText_Flag)) {
2732 width = paint.measureText(text, byteLength);
2733
2734 SkScalar offsetX = 0;
2735 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2736 offsetX = SkScalarHalf(width);
2737 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2738 offsetX = width;
2739 }
2740 start.set(x - offsetX, y);
2741 }
2742
2743 if (0 == width) {
2744 return;
2745 }
2746
2747 uint32_t flags = paint.getFlags();
2748
2749 if (flags & (SkPaint::kUnderlineText_Flag |
2750 SkPaint::kStrikeThruText_Flag)) {
2751 SkScalar textSize = paint.getTextSize();
2752 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2753 SkRect r;
2754
2755 r.fLeft = start.fX;
2756 r.fRight = start.fX + width;
2757
2758 if (flags & SkPaint::kUnderlineText_Flag) {
2759 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2760 start.fY);
2761 r.fTop = offset;
2762 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002763 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002764 }
2765 if (flags & SkPaint::kStrikeThruText_Flag) {
2766 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2767 start.fY);
2768 r.fTop = offset;
2769 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002770 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002771 }
2772 }
2773}
2774
reed@google.come0d9ce82014-04-23 04:00:17 +00002775void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2776 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002777 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002778
2779 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002780 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002781 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002782 DrawTextDecorations(iter, dfp.paint(),
2783 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784 }
2785
reed@google.com4e2b3d32011-04-07 14:18:59 +00002786 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002787}
2788
reed@google.come0d9ce82014-04-23 04:00:17 +00002789void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2790 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002791 SkPoint textOffset = SkPoint::Make(0, 0);
2792
halcanary96fcdcc2015-08-27 07:41:13 -07002793 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002794
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002796 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002797 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002798 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002799 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002800
reed@google.com4e2b3d32011-04-07 14:18:59 +00002801 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002802}
2803
reed@google.come0d9ce82014-04-23 04:00:17 +00002804void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2805 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002806
2807 SkPoint textOffset = SkPoint::Make(0, constY);
2808
halcanary96fcdcc2015-08-27 07:41:13 -07002809 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002810
reed@android.com8a1c16f2008-12-17 15:59:43 +00002811 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002812 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002813 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002814 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002815 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002816
reed@google.com4e2b3d32011-04-07 14:18:59 +00002817 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002818}
2819
reed@google.come0d9ce82014-04-23 04:00:17 +00002820void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2821 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002822 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002823
reed@android.com8a1c16f2008-12-17 15:59:43 +00002824 while (iter.next()) {
2825 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002826 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002827 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002828
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002829 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002830}
2831
reed45561a02016-07-07 12:47:17 -07002832void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2833 const SkRect* cullRect, const SkPaint& paint) {
2834 if (cullRect && this->quickReject(*cullRect)) {
2835 return;
2836 }
2837
2838 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2839
2840 while (iter.next()) {
2841 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2842 }
2843
2844 LOOPER_END
2845}
2846
fmalita00d5c2c2014-08-21 08:53:26 -07002847void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2848 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002849
fmalita85d5eb92015-03-04 11:20:12 -08002850 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002851 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002852 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002853 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002854 SkRect tmp;
2855 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2856 return;
2857 }
2858 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002859 }
2860
fmalita024f9962015-03-03 19:08:17 -08002861 // We cannot filter in the looper as we normally do, because the paint is
2862 // incomplete at this point (text-related attributes are embedded within blob run paints).
2863 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002864 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002865
fmalita85d5eb92015-03-04 11:20:12 -08002866 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002867
fmalitaaa1b9122014-08-28 14:32:24 -07002868 while (iter.next()) {
2869 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002870 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002871 }
2872
fmalitaaa1b9122014-08-28 14:32:24 -07002873 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002874
2875 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002876}
2877
reed@google.come0d9ce82014-04-23 04:00:17 +00002878// These will become non-virtual, so they always call the (virtual) onDraw... method
2879void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2880 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002881 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002882 if (byteLength) {
2883 this->onDrawText(text, byteLength, x, y, paint);
2884 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002885}
2886void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2887 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002888 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002889 if (byteLength) {
2890 this->onDrawPosText(text, byteLength, pos, paint);
2891 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002892}
2893void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2894 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002895 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002896 if (byteLength) {
2897 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2898 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002899}
2900void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2901 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002902 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002903 if (byteLength) {
2904 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2905 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002906}
reed45561a02016-07-07 12:47:17 -07002907void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2908 const SkRect* cullRect, const SkPaint& paint) {
2909 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2910 if (byteLength) {
2911 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2912 }
2913}
fmalita00d5c2c2014-08-21 08:53:26 -07002914void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2915 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002916 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002917 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002918 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002919}
reed@google.come0d9ce82014-04-23 04:00:17 +00002920
reed41af9662015-01-05 07:49:08 -08002921void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2922 const SkPoint verts[], const SkPoint texs[],
2923 const SkColor colors[], SkXfermode* xmode,
2924 const uint16_t indices[], int indexCount,
2925 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002926 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002927 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002928
reed@android.com8a1c16f2008-12-17 15:59:43 +00002929 while (iter.next()) {
2930 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002931 colors, xmode, indices, indexCount,
2932 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002933 }
reed@google.com4b226022011-01-11 18:32:13 +00002934
reed@google.com4e2b3d32011-04-07 14:18:59 +00002935 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002936}
2937
dandovb3c9d1c2014-08-12 08:34:29 -07002938void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2939 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002940 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002941 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002942 return;
2943 }
mtklein6cfa73a2014-08-13 13:33:49 -07002944
dandovecfff212014-08-04 10:02:00 -07002945 // Since a patch is always within the convex hull of the control points, we discard it when its
2946 // bounding rectangle is completely outside the current clip.
2947 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002948 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002949 if (this->quickReject(bounds)) {
2950 return;
2951 }
mtklein6cfa73a2014-08-13 13:33:49 -07002952
dandovb3c9d1c2014-08-12 08:34:29 -07002953 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2954}
2955
2956void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2957 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2958
halcanary96fcdcc2015-08-27 07:41:13 -07002959 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002960
dandovecfff212014-08-04 10:02:00 -07002961 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002962 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002963 }
mtklein6cfa73a2014-08-13 13:33:49 -07002964
dandovecfff212014-08-04 10:02:00 -07002965 LOOPER_END
2966}
2967
reeda8db7282015-07-07 10:22:31 -07002968void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002969 RETURN_ON_NULL(dr);
2970 if (x || y) {
2971 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2972 this->onDrawDrawable(dr, &matrix);
2973 } else {
2974 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002975 }
2976}
2977
reeda8db7282015-07-07 10:22:31 -07002978void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002979 RETURN_ON_NULL(dr);
2980 if (matrix && matrix->isIdentity()) {
2981 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002982 }
reede3b38ce2016-01-08 09:18:44 -08002983 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002984}
2985
2986void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2987 SkRect bounds = dr->getBounds();
2988 if (matrix) {
2989 matrix->mapRect(&bounds);
2990 }
2991 if (this->quickReject(bounds)) {
2992 return;
2993 }
2994 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002995}
2996
reed71c3c762015-06-24 10:29:17 -07002997void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2998 const SkColor colors[], int count, SkXfermode::Mode mode,
2999 const SkRect* cull, const SkPaint* paint) {
3000 if (cull && this->quickReject(*cull)) {
3001 return;
3002 }
3003
3004 SkPaint pnt;
3005 if (paint) {
3006 pnt = *paint;
3007 }
halcanary9d524f22016-03-29 09:03:52 -07003008
halcanary96fcdcc2015-08-27 07:41:13 -07003009 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07003010 while (iter.next()) {
3011 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
3012 }
3013 LOOPER_END
3014}
3015
reedf70b5312016-03-04 16:36:20 -08003016void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
3017 SkASSERT(key);
3018
3019 SkPaint paint;
3020 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
3021 while (iter.next()) {
3022 iter.fDevice->drawAnnotation(iter, rect, key, value);
3023 }
3024 LOOPER_END
3025}
3026
reed@android.com8a1c16f2008-12-17 15:59:43 +00003027//////////////////////////////////////////////////////////////////////////////
3028// These methods are NOT virtual, and therefore must call back into virtual
3029// methods, rather than actually drawing themselves.
3030//////////////////////////////////////////////////////////////////////////////
3031
3032void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00003033 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003034 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003035 SkPaint paint;
3036
3037 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00003038 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003039 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003040 }
3041 this->drawPaint(paint);
3042}
3043
reed@android.com845fdac2009-06-23 03:01:32 +00003044void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003045 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003046 SkPaint paint;
3047
3048 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00003049 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003050 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003051 }
3052 this->drawPaint(paint);
3053}
3054
3055void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003056 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003057 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00003058
reed@android.com8a1c16f2008-12-17 15:59:43 +00003059 pt.set(x, y);
3060 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3061}
3062
3063void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08003064 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003065 SkPoint pt;
3066 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00003067
reed@android.com8a1c16f2008-12-17 15:59:43 +00003068 pt.set(x, y);
3069 paint.setColor(color);
3070 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3071}
3072
3073void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
3074 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003075 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003076 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003077
reed@android.com8a1c16f2008-12-17 15:59:43 +00003078 pts[0].set(x0, y0);
3079 pts[1].set(x1, y1);
3080 this->drawPoints(kLines_PointMode, 2, pts, paint);
3081}
3082
3083void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3084 SkScalar right, SkScalar bottom,
3085 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003086 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003087 SkRect r;
3088
3089 r.set(left, top, right, bottom);
3090 this->drawRect(r, paint);
3091}
3092
3093void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3094 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003095 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003096 if (radius < 0) {
3097 radius = 0;
3098 }
3099
3100 SkRect r;
3101 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003102 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003103}
3104
3105void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3106 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003107 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003108 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003109 SkRRect rrect;
3110 rrect.setRectXY(r, rx, ry);
3111 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003112 } else {
3113 this->drawRect(r, paint);
3114 }
3115}
3116
reed@android.com8a1c16f2008-12-17 15:59:43 +00003117void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3118 SkScalar sweepAngle, bool useCenter,
3119 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003120 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003121 if (oval.isEmpty() || !sweepAngle) {
3122 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003123 }
bsalomon21af9ca2016-08-25 12:29:23 -07003124 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003125}
3126
3127void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3128 const SkPath& path, SkScalar hOffset,
3129 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003130 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003131 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003132
reed@android.com8a1c16f2008-12-17 15:59:43 +00003133 matrix.setTranslate(hOffset, vOffset);
3134 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3135}
3136
reed@android.comf76bacf2009-05-13 14:00:33 +00003137///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003138
3139/**
3140 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3141 * against the playback cost of recursing into the subpicture to get at its actual ops.
3142 *
3143 * For now we pick a conservatively small value, though measurement (and other heuristics like
3144 * the type of ops contained) may justify changing this value.
3145 */
3146#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003147
reedd5fa1a42014-08-09 11:08:05 -07003148void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003149 RETURN_ON_NULL(picture);
3150
reed1c2c4412015-04-30 13:09:24 -07003151 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003152 if (matrix && matrix->isIdentity()) {
3153 matrix = nullptr;
3154 }
3155 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3156 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3157 picture->playback(this);
3158 } else {
3159 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003160 }
3161}
robertphillips9b14f262014-06-04 05:40:44 -07003162
reedd5fa1a42014-08-09 11:08:05 -07003163void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3164 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003165 if (!paint || paint->canComputeFastBounds()) {
3166 SkRect bounds = picture->cullRect();
3167 if (paint) {
3168 paint->computeFastBounds(bounds, &bounds);
3169 }
3170 if (matrix) {
3171 matrix->mapRect(&bounds);
3172 }
3173 if (this->quickReject(bounds)) {
3174 return;
3175 }
3176 }
3177
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003178 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003179 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003180}
3181
vjiaoblack95302da2016-07-21 10:25:54 -07003182#ifdef SK_EXPERIMENTAL_SHADOWING
3183void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3184 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003185 const SkPaint* paint,
3186 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003187 RETURN_ON_NULL(picture);
3188
3189 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3190
vjiaoblacke6f5d562016-08-25 06:30:23 -07003191 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003192}
3193
3194void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3195 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003196 const SkPaint* paint,
3197 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003198 if (!paint || paint->canComputeFastBounds()) {
3199 SkRect bounds = picture->cullRect();
3200 if (paint) {
3201 paint->computeFastBounds(bounds, &bounds);
3202 }
3203 if (matrix) {
3204 matrix->mapRect(&bounds);
3205 }
3206 if (this->quickReject(bounds)) {
3207 return;
3208 }
3209 }
3210
3211 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3212
vjiaoblacke6f5d562016-08-25 06:30:23 -07003213 sk_sp<SkImage> povDepthMap;
3214 sk_sp<SkImage> diffuseMap;
3215
3216 // TODO: pass the depth to the shader in vertices, or uniforms
3217 // so we don't have to render depth and color separately
vjiaoblack904527d2016-08-09 09:32:09 -07003218 for (int i = 0; i < fLights->numLights(); ++i) {
3219 // skip over ambient lights; they don't cast shadows
3220 // lights that have shadow maps do not need updating (because lights are immutable)
3221
3222 if (SkLights::Light::kAmbient_LightType == fLights->light(i).type() ||
3223 fLights->light(i).getShadowMap() != nullptr) {
3224 continue;
3225 }
3226
3227 // TODO: compute the correct size of the depth map from the light properties
3228 // TODO: maybe add a kDepth_8_SkColorType
3229 // TODO: find actual max depth of picture
3230 SkISize shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3231 fLights->light(i), 255,
3232 picture->cullRect().width(),
3233 picture->cullRect().height());
3234
3235 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3236 kBGRA_8888_SkColorType,
3237 kOpaque_SkAlphaType);
3238
3239 // Create a new surface (that matches the backend of canvas)
3240 // for each shadow map
3241 sk_sp<SkSurface> surf(this->makeSurface(info));
3242
3243 // Wrap another SPFCanvas around the surface
3244 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3245 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
vjiaoblacke6f5d562016-08-25 06:30:23 -07003246 depthMapCanvas->setShadowParams(params);
vjiaoblack904527d2016-08-09 09:32:09 -07003247
3248 // set the depth map canvas to have the light we're drawing.
3249 SkLights::Builder builder;
3250 builder.add(fLights->light(i));
3251 sk_sp<SkLights> curLight = builder.finish();
vjiaoblack904527d2016-08-09 09:32:09 -07003252 depthMapCanvas->setLights(std::move(curLight));
vjiaoblacke6f5d562016-08-25 06:30:23 -07003253
vjiaoblack904527d2016-08-09 09:32:09 -07003254 depthMapCanvas->drawPicture(picture);
vjiaoblacke6f5d562016-08-25 06:30:23 -07003255 sk_sp<SkImage> depthMap = surf->makeImageSnapshot();
vjiaoblack904527d2016-08-09 09:32:09 -07003256
vjiaoblacke6f5d562016-08-25 06:30:23 -07003257 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3258 fLights->light(i).setShadowMap(std::move(depthMap));
3259 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3260 // we blur the variance map
3261 SkPaint blurPaint;
3262 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3263 params.fShadowRadius, nullptr));
3264
3265 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3266 kBGRA_8888_SkColorType,
3267 kOpaque_SkAlphaType);
3268
3269 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3270
3271 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3272
3273 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3274 }
vjiaoblack904527d2016-08-09 09:32:09 -07003275 }
3276
vjiaoblack904527d2016-08-09 09:32:09 -07003277 // povDepthMap
3278 {
3279 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003280 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3281 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003282 sk_sp<SkLights> povLight = builder.finish();
3283
3284 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3285 picture->cullRect().height(),
3286 kBGRA_8888_SkColorType,
3287 kOpaque_SkAlphaType);
3288
3289 // Create a new surface (that matches the backend of canvas)
3290 // to create the povDepthMap
3291 sk_sp<SkSurface> surf(this->makeSurface(info));
3292
3293 // Wrap another SPFCanvas around the surface
3294 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3295 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3296
3297 // set the depth map canvas to have the light as the user's POV
3298 depthMapCanvas->setLights(std::move(povLight));
3299
3300 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003301 povDepthMap = surf->makeImageSnapshot();
3302 }
3303
3304 // diffuseMap
3305 {
3306 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3307 picture->cullRect().height(),
3308 kBGRA_8888_SkColorType,
3309 kOpaque_SkAlphaType);
3310
3311 sk_sp<SkSurface> surf(this->makeSurface(info));
3312 surf->getCanvas()->drawPicture(picture);
3313
3314 diffuseMap = surf->makeImageSnapshot();
3315 }
vjiaoblack904527d2016-08-09 09:32:09 -07003316 SkPaint shadowPaint;
3317
3318 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3319 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003320 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3321 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003322 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3323 std::move(diffuseShader),
3324 std::move(fLights),
3325 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003326 diffuseMap->height(),
3327 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003328
3329 shadowPaint.setShader(shadowShader);
3330
3331 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003332}
3333#endif
3334
reed@android.com8a1c16f2008-12-17 15:59:43 +00003335///////////////////////////////////////////////////////////////////////////////
3336///////////////////////////////////////////////////////////////////////////////
3337
reed3aafe112016-08-18 12:45:34 -07003338SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003339 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003340
3341 SkASSERT(canvas);
3342
reed3aafe112016-08-18 12:45:34 -07003343 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003344 fDone = !fImpl->next();
3345}
3346
3347SkCanvas::LayerIter::~LayerIter() {
3348 fImpl->~SkDrawIter();
3349}
3350
3351void SkCanvas::LayerIter::next() {
3352 fDone = !fImpl->next();
3353}
3354
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003355SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003356 return fImpl->getDevice();
3357}
3358
3359const SkMatrix& SkCanvas::LayerIter::matrix() const {
3360 return fImpl->getMatrix();
3361}
3362
3363const SkPaint& SkCanvas::LayerIter::paint() const {
3364 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003365 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003366 paint = &fDefaultPaint;
3367 }
3368 return *paint;
3369}
3370
reed1e7f5e72016-04-27 07:49:17 -07003371const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003372int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3373int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003374
3375///////////////////////////////////////////////////////////////////////////////
3376
fmalitac3b589a2014-06-05 12:40:07 -07003377SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003378
3379///////////////////////////////////////////////////////////////////////////////
3380
3381static bool supported_for_raster_canvas(const SkImageInfo& info) {
3382 switch (info.alphaType()) {
3383 case kPremul_SkAlphaType:
3384 case kOpaque_SkAlphaType:
3385 break;
3386 default:
3387 return false;
3388 }
3389
3390 switch (info.colorType()) {
3391 case kAlpha_8_SkColorType:
3392 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003393 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003394 break;
3395 default:
3396 return false;
3397 }
3398
3399 return true;
3400}
3401
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003402SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3403 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003404 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003405 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003406
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003407 SkBitmap bitmap;
3408 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003409 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003410 }
halcanary385fe4d2015-08-26 13:07:48 -07003411 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003412}
reedd5fa1a42014-08-09 11:08:05 -07003413
3414///////////////////////////////////////////////////////////////////////////////
3415
3416SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003417 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003418 : fCanvas(canvas)
3419 , fSaveCount(canvas->getSaveCount())
3420{
bsalomon49f085d2014-09-05 13:34:00 -07003421 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003422 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003423 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003424 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003425 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003426 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003427 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003428 canvas->save();
3429 }
mtklein6cfa73a2014-08-13 13:33:49 -07003430
bsalomon49f085d2014-09-05 13:34:00 -07003431 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003432 canvas->concat(*matrix);
3433 }
3434}
3435
3436SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3437 fCanvas->restoreToCount(fSaveCount);
3438}
reede8f30622016-03-23 18:59:25 -07003439
3440#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3441SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
3442 return this->makeSurface(info, props).release();
3443}
3444#endif