blob: 8f9a576761afd4ffeb8181dcb7bb45a6be74307c [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
reed41af9662015-01-05 07:49:08 -08002253void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002254 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002255 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002256 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002257 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002258 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2259 return;
2260 }
2261 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002262 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002263
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002264 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002265
2266 while (iter.next()) {
2267 iter.fDevice->drawOval(iter, oval, looper.paint());
2268 }
2269
2270 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002271}
2272
bsalomonac3aa242016-08-19 11:25:19 -07002273void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2274 SkScalar sweepAngle, bool useCenter,
2275 const SkPaint& paint) {
2276 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2277 const SkRect* bounds = nullptr;
2278 if (paint.canComputeFastBounds()) {
2279 SkRect storage;
2280 // Note we're using the entire oval as the bounds.
2281 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2282 return;
2283 }
2284 bounds = &oval;
2285 }
2286
2287 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2288
2289 while (iter.next()) {
2290 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2291 }
2292
2293 LOOPER_END
2294}
2295
reed41af9662015-01-05 07:49:08 -08002296void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002297 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002298 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002299 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002300 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002301 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2302 return;
2303 }
2304 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002305 }
2306
2307 if (rrect.isRect()) {
2308 // call the non-virtual version
2309 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002310 return;
2311 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002312 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002313 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2314 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002315 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002316
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002317 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002318
2319 while (iter.next()) {
2320 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2321 }
2322
2323 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002324}
2325
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002326void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2327 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002328 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002329 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002330 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002331 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2332 return;
2333 }
2334 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002335 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002336
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002337 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002338
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002339 while (iter.next()) {
2340 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2341 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002342
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002343 LOOPER_END
2344}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002345
reed41af9662015-01-05 07:49:08 -08002346void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002347 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002348 if (!path.isFinite()) {
2349 return;
2350 }
2351
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002352 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002353 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002354 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002355 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002356 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2357 return;
2358 }
2359 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002360 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002361
2362 const SkRect& r = path.getBounds();
2363 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002364 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002365 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002366 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002367 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002368 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002369
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002370 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002371
2372 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002373 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002374 }
2375
reed@google.com4e2b3d32011-04-07 14:18:59 +00002376 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002377}
2378
reed262a71b2015-12-05 13:07:27 -08002379bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002380 if (!paint.getImageFilter()) {
2381 return false;
2382 }
2383
2384 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002385 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002386 return false;
2387 }
2388
2389 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2390 // Once we can filter and the filter will return a result larger than itself, we should be
2391 // able to remove this constraint.
2392 // skbug.com/4526
2393 //
2394 SkPoint pt;
2395 ctm.mapXY(x, y, &pt);
2396 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2397 return ir.contains(fMCRec->fRasterClip.getBounds());
2398}
2399
reeda85d4d02015-05-06 12:56:48 -07002400void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002401 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002402 SkRect bounds = SkRect::MakeXYWH(x, y,
2403 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002404 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002405 SkRect tmp = bounds;
2406 if (paint) {
2407 paint->computeFastBounds(tmp, &tmp);
2408 }
2409 if (this->quickReject(tmp)) {
2410 return;
2411 }
reeda85d4d02015-05-06 12:56:48 -07002412 }
halcanary9d524f22016-03-29 09:03:52 -07002413
reeda85d4d02015-05-06 12:56:48 -07002414 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002415 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002416 paint = lazy.init();
2417 }
reed262a71b2015-12-05 13:07:27 -08002418
reeda2217ef2016-07-20 06:04:34 -07002419 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002420 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2421 *paint);
2422 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002423 special = this->getDevice()->makeSpecial(image);
2424 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002425 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002426 }
2427 }
2428
reed262a71b2015-12-05 13:07:27 -08002429 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2430
reeda85d4d02015-05-06 12:56:48 -07002431 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002432 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002433 if (special) {
2434 SkPoint pt;
2435 iter.fMatrix->mapXY(x, y, &pt);
2436 iter.fDevice->drawSpecial(iter, special.get(),
2437 SkScalarRoundToInt(pt.fX),
2438 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002439 } else {
2440 iter.fDevice->drawImage(iter, image, x, y, pnt);
2441 }
reeda85d4d02015-05-06 12:56:48 -07002442 }
halcanary9d524f22016-03-29 09:03:52 -07002443
reeda85d4d02015-05-06 12:56:48 -07002444 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002445}
2446
reed41af9662015-01-05 07:49:08 -08002447void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002448 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002449 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002450 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002451 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002452 if (paint) {
2453 paint->computeFastBounds(dst, &storage);
2454 }
2455 if (this->quickReject(storage)) {
2456 return;
2457 }
reeda85d4d02015-05-06 12:56:48 -07002458 }
2459 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002460 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002461 paint = lazy.init();
2462 }
halcanary9d524f22016-03-29 09:03:52 -07002463
senorblancoc41e7e12015-12-07 12:51:30 -08002464 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002465 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002466
reeda85d4d02015-05-06 12:56:48 -07002467 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002468 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002469 }
halcanary9d524f22016-03-29 09:03:52 -07002470
reeda85d4d02015-05-06 12:56:48 -07002471 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002472}
2473
reed41af9662015-01-05 07:49:08 -08002474void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002475 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002476 SkDEBUGCODE(bitmap.validate();)
2477
reed33366972015-10-08 09:22:02 -07002478 if (bitmap.drawsNothing()) {
2479 return;
2480 }
2481
2482 SkLazyPaint lazy;
2483 if (nullptr == paint) {
2484 paint = lazy.init();
2485 }
2486
2487 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2488
2489 SkRect storage;
2490 const SkRect* bounds = nullptr;
2491 if (paint->canComputeFastBounds()) {
2492 bitmap.getBounds(&storage);
2493 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002494 SkRect tmp = storage;
2495 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2496 return;
2497 }
2498 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002499 }
reed@google.com4b226022011-01-11 18:32:13 +00002500
reeda2217ef2016-07-20 06:04:34 -07002501 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002502 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2503 *paint);
2504 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002505 special = this->getDevice()->makeSpecial(bitmap);
2506 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002507 drawAsSprite = false;
2508 }
2509 }
2510
reed262a71b2015-12-05 13:07:27 -08002511 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002512
2513 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002514 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002515 if (special) {
reed262a71b2015-12-05 13:07:27 -08002516 SkPoint pt;
2517 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002518 iter.fDevice->drawSpecial(iter, special.get(),
2519 SkScalarRoundToInt(pt.fX),
2520 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002521 } else {
2522 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2523 }
reed33366972015-10-08 09:22:02 -07002524 }
msarettfbfa2582016-08-12 08:29:08 -07002525
reed33366972015-10-08 09:22:02 -07002526 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002527}
2528
reed@google.com9987ec32011-09-07 11:57:52 +00002529// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002530void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002531 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002532 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002533 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002534 return;
2535 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002536
halcanary96fcdcc2015-08-27 07:41:13 -07002537 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002538 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002539 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2540 return;
2541 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002542 }
reed@google.com3d608122011-11-21 15:16:16 +00002543
reed@google.com33535f32012-09-25 15:37:50 +00002544 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002545 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002546 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002547 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002548
senorblancoc41e7e12015-12-07 12:51:30 -08002549 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002550 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002551
reed@google.com33535f32012-09-25 15:37:50 +00002552 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002553 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002554 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002555
reed@google.com33535f32012-09-25 15:37:50 +00002556 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002557}
2558
reed41af9662015-01-05 07:49:08 -08002559void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002560 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002561 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002562 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002563 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002564}
2565
reed4c21dc52015-06-25 12:32:03 -07002566void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2567 const SkPaint* paint) {
2568 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002569
halcanary96fcdcc2015-08-27 07:41:13 -07002570 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002571 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002572 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2573 return;
2574 }
reed@google.com3d608122011-11-21 15:16:16 +00002575 }
halcanary9d524f22016-03-29 09:03:52 -07002576
reed4c21dc52015-06-25 12:32:03 -07002577 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002578 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002579 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002580 }
halcanary9d524f22016-03-29 09:03:52 -07002581
senorblancoc41e7e12015-12-07 12:51:30 -08002582 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002583
reed4c21dc52015-06-25 12:32:03 -07002584 while (iter.next()) {
2585 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002586 }
halcanary9d524f22016-03-29 09:03:52 -07002587
reed4c21dc52015-06-25 12:32:03 -07002588 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002589}
2590
reed41af9662015-01-05 07:49:08 -08002591void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2592 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002593 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002594 SkDEBUGCODE(bitmap.validate();)
2595
halcanary96fcdcc2015-08-27 07:41:13 -07002596 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002597 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002598 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2599 return;
2600 }
reed4c21dc52015-06-25 12:32:03 -07002601 }
halcanary9d524f22016-03-29 09:03:52 -07002602
reed4c21dc52015-06-25 12:32:03 -07002603 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002604 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002605 paint = lazy.init();
2606 }
halcanary9d524f22016-03-29 09:03:52 -07002607
senorblancoc41e7e12015-12-07 12:51:30 -08002608 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002609
reed4c21dc52015-06-25 12:32:03 -07002610 while (iter.next()) {
2611 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2612 }
halcanary9d524f22016-03-29 09:03:52 -07002613
reed4c21dc52015-06-25 12:32:03 -07002614 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002615}
2616
msarett16882062016-08-16 09:31:08 -07002617void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2618 const SkPaint* paint) {
2619 if (nullptr == paint || paint->canComputeFastBounds()) {
2620 SkRect storage;
2621 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2622 return;
2623 }
2624 }
2625
2626 SkLazyPaint lazy;
2627 if (nullptr == paint) {
2628 paint = lazy.init();
2629 }
2630
2631 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2632
2633 while (iter.next()) {
2634 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2635 }
2636
2637 LOOPER_END
2638}
2639
2640void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2641 const SkRect& dst, const SkPaint* paint) {
2642 if (nullptr == paint || paint->canComputeFastBounds()) {
2643 SkRect storage;
2644 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2645 return;
2646 }
2647 }
2648
2649 SkLazyPaint lazy;
2650 if (nullptr == paint) {
2651 paint = lazy.init();
2652 }
2653
2654 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2655
2656 while (iter.next()) {
2657 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2658 }
2659
2660 LOOPER_END
2661}
2662
reed@google.comf67e4cf2011-03-15 20:56:58 +00002663class SkDeviceFilteredPaint {
2664public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002665 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002666 uint32_t filteredFlags = device->filterTextFlags(paint);
2667 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002668 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002669 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002670 fPaint = newPaint;
2671 } else {
2672 fPaint = &paint;
2673 }
2674 }
2675
reed@google.comf67e4cf2011-03-15 20:56:58 +00002676 const SkPaint& paint() const { return *fPaint; }
2677
2678private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002679 const SkPaint* fPaint;
2680 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002681};
2682
bungeman@google.com52c748b2011-08-22 21:30:43 +00002683void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2684 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002685 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002686 draw.fDevice->drawRect(draw, r, paint);
2687 } else {
2688 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002689 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002690 draw.fDevice->drawRect(draw, r, p);
2691 }
2692}
2693
2694void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2695 const char text[], size_t byteLength,
2696 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002697 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002698
2699 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002700 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002701 draw.fRC->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002702 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002703 return;
2704 }
2705
2706 SkScalar width = 0;
2707 SkPoint start;
2708
2709 start.set(0, 0); // to avoid warning
2710 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2711 SkPaint::kStrikeThruText_Flag)) {
2712 width = paint.measureText(text, byteLength);
2713
2714 SkScalar offsetX = 0;
2715 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2716 offsetX = SkScalarHalf(width);
2717 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2718 offsetX = width;
2719 }
2720 start.set(x - offsetX, y);
2721 }
2722
2723 if (0 == width) {
2724 return;
2725 }
2726
2727 uint32_t flags = paint.getFlags();
2728
2729 if (flags & (SkPaint::kUnderlineText_Flag |
2730 SkPaint::kStrikeThruText_Flag)) {
2731 SkScalar textSize = paint.getTextSize();
2732 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2733 SkRect r;
2734
2735 r.fLeft = start.fX;
2736 r.fRight = start.fX + width;
2737
2738 if (flags & SkPaint::kUnderlineText_Flag) {
2739 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2740 start.fY);
2741 r.fTop = offset;
2742 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002743 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002744 }
2745 if (flags & SkPaint::kStrikeThruText_Flag) {
2746 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2747 start.fY);
2748 r.fTop = offset;
2749 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002750 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002751 }
2752 }
2753}
2754
reed@google.come0d9ce82014-04-23 04:00:17 +00002755void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2756 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002757 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002758
2759 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002760 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002761 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002762 DrawTextDecorations(iter, dfp.paint(),
2763 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764 }
2765
reed@google.com4e2b3d32011-04-07 14:18:59 +00002766 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002767}
2768
reed@google.come0d9ce82014-04-23 04:00:17 +00002769void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2770 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002771 SkPoint textOffset = SkPoint::Make(0, 0);
2772
halcanary96fcdcc2015-08-27 07:41:13 -07002773 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002774
reed@android.com8a1c16f2008-12-17 15:59:43 +00002775 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002776 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002777 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002778 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002779 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002780
reed@google.com4e2b3d32011-04-07 14:18:59 +00002781 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782}
2783
reed@google.come0d9ce82014-04-23 04:00:17 +00002784void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2785 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002786
2787 SkPoint textOffset = SkPoint::Make(0, constY);
2788
halcanary96fcdcc2015-08-27 07:41:13 -07002789 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002790
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002792 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002793 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002794 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002796
reed@google.com4e2b3d32011-04-07 14:18:59 +00002797 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002798}
2799
reed@google.come0d9ce82014-04-23 04:00:17 +00002800void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2801 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002802 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002803
reed@android.com8a1c16f2008-12-17 15:59:43 +00002804 while (iter.next()) {
2805 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002806 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002808
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002809 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002810}
2811
reed45561a02016-07-07 12:47:17 -07002812void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2813 const SkRect* cullRect, const SkPaint& paint) {
2814 if (cullRect && this->quickReject(*cullRect)) {
2815 return;
2816 }
2817
2818 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2819
2820 while (iter.next()) {
2821 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2822 }
2823
2824 LOOPER_END
2825}
2826
fmalita00d5c2c2014-08-21 08:53:26 -07002827void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2828 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002829
fmalita85d5eb92015-03-04 11:20:12 -08002830 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002831 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002832 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002833 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002834 SkRect tmp;
2835 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2836 return;
2837 }
2838 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002839 }
2840
fmalita024f9962015-03-03 19:08:17 -08002841 // We cannot filter in the looper as we normally do, because the paint is
2842 // incomplete at this point (text-related attributes are embedded within blob run paints).
2843 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002844 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002845
fmalita85d5eb92015-03-04 11:20:12 -08002846 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002847
fmalitaaa1b9122014-08-28 14:32:24 -07002848 while (iter.next()) {
2849 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002850 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002851 }
2852
fmalitaaa1b9122014-08-28 14:32:24 -07002853 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002854
2855 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002856}
2857
reed@google.come0d9ce82014-04-23 04:00:17 +00002858// These will become non-virtual, so they always call the (virtual) onDraw... method
2859void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2860 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002861 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002862 if (byteLength) {
2863 this->onDrawText(text, byteLength, x, y, paint);
2864 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002865}
2866void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2867 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002868 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002869 if (byteLength) {
2870 this->onDrawPosText(text, byteLength, pos, paint);
2871 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002872}
2873void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2874 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002875 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002876 if (byteLength) {
2877 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2878 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002879}
2880void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2881 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002882 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002883 if (byteLength) {
2884 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2885 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002886}
reed45561a02016-07-07 12:47:17 -07002887void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2888 const SkRect* cullRect, const SkPaint& paint) {
2889 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2890 if (byteLength) {
2891 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2892 }
2893}
fmalita00d5c2c2014-08-21 08:53:26 -07002894void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2895 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002896 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002897 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002898 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002899}
reed@google.come0d9ce82014-04-23 04:00:17 +00002900
reed41af9662015-01-05 07:49:08 -08002901void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2902 const SkPoint verts[], const SkPoint texs[],
2903 const SkColor colors[], SkXfermode* xmode,
2904 const uint16_t indices[], int indexCount,
2905 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002906 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002907 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002908
reed@android.com8a1c16f2008-12-17 15:59:43 +00002909 while (iter.next()) {
2910 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002911 colors, xmode, indices, indexCount,
2912 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002913 }
reed@google.com4b226022011-01-11 18:32:13 +00002914
reed@google.com4e2b3d32011-04-07 14:18:59 +00002915 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002916}
2917
dandovb3c9d1c2014-08-12 08:34:29 -07002918void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2919 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002920 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002921 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002922 return;
2923 }
mtklein6cfa73a2014-08-13 13:33:49 -07002924
dandovecfff212014-08-04 10:02:00 -07002925 // Since a patch is always within the convex hull of the control points, we discard it when its
2926 // bounding rectangle is completely outside the current clip.
2927 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002928 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002929 if (this->quickReject(bounds)) {
2930 return;
2931 }
mtklein6cfa73a2014-08-13 13:33:49 -07002932
dandovb3c9d1c2014-08-12 08:34:29 -07002933 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2934}
2935
2936void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2937 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2938
halcanary96fcdcc2015-08-27 07:41:13 -07002939 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002940
dandovecfff212014-08-04 10:02:00 -07002941 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002942 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002943 }
mtklein6cfa73a2014-08-13 13:33:49 -07002944
dandovecfff212014-08-04 10:02:00 -07002945 LOOPER_END
2946}
2947
reeda8db7282015-07-07 10:22:31 -07002948void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002949 RETURN_ON_NULL(dr);
2950 if (x || y) {
2951 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2952 this->onDrawDrawable(dr, &matrix);
2953 } else {
2954 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002955 }
2956}
2957
reeda8db7282015-07-07 10:22:31 -07002958void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002959 RETURN_ON_NULL(dr);
2960 if (matrix && matrix->isIdentity()) {
2961 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002962 }
reede3b38ce2016-01-08 09:18:44 -08002963 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002964}
2965
2966void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2967 SkRect bounds = dr->getBounds();
2968 if (matrix) {
2969 matrix->mapRect(&bounds);
2970 }
2971 if (this->quickReject(bounds)) {
2972 return;
2973 }
2974 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002975}
2976
reed71c3c762015-06-24 10:29:17 -07002977void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2978 const SkColor colors[], int count, SkXfermode::Mode mode,
2979 const SkRect* cull, const SkPaint* paint) {
2980 if (cull && this->quickReject(*cull)) {
2981 return;
2982 }
2983
2984 SkPaint pnt;
2985 if (paint) {
2986 pnt = *paint;
2987 }
halcanary9d524f22016-03-29 09:03:52 -07002988
halcanary96fcdcc2015-08-27 07:41:13 -07002989 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002990 while (iter.next()) {
2991 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2992 }
2993 LOOPER_END
2994}
2995
reedf70b5312016-03-04 16:36:20 -08002996void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2997 SkASSERT(key);
2998
2999 SkPaint paint;
3000 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
3001 while (iter.next()) {
3002 iter.fDevice->drawAnnotation(iter, rect, key, value);
3003 }
3004 LOOPER_END
3005}
3006
reed@android.com8a1c16f2008-12-17 15:59:43 +00003007//////////////////////////////////////////////////////////////////////////////
3008// These methods are NOT virtual, and therefore must call back into virtual
3009// methods, rather than actually drawing themselves.
3010//////////////////////////////////////////////////////////////////////////////
3011
3012void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00003013 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003014 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003015 SkPaint paint;
3016
3017 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00003018 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003019 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003020 }
3021 this->drawPaint(paint);
3022}
3023
reed@android.com845fdac2009-06-23 03:01:32 +00003024void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003025 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003026 SkPaint paint;
3027
3028 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00003029 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003030 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003031 }
3032 this->drawPaint(paint);
3033}
3034
3035void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003036 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003037 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00003038
reed@android.com8a1c16f2008-12-17 15:59:43 +00003039 pt.set(x, y);
3040 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3041}
3042
3043void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08003044 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003045 SkPoint pt;
3046 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00003047
reed@android.com8a1c16f2008-12-17 15:59:43 +00003048 pt.set(x, y);
3049 paint.setColor(color);
3050 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3051}
3052
3053void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
3054 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003055 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003056 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003057
reed@android.com8a1c16f2008-12-17 15:59:43 +00003058 pts[0].set(x0, y0);
3059 pts[1].set(x1, y1);
3060 this->drawPoints(kLines_PointMode, 2, pts, paint);
3061}
3062
3063void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3064 SkScalar right, SkScalar bottom,
3065 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003066 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003067 SkRect r;
3068
3069 r.set(left, top, right, bottom);
3070 this->drawRect(r, paint);
3071}
3072
3073void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3074 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003075 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003076 if (radius < 0) {
3077 radius = 0;
3078 }
3079
3080 SkRect r;
3081 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003082 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003083}
3084
3085void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3086 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003087 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003088 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003089 SkRRect rrect;
3090 rrect.setRectXY(r, rx, ry);
3091 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003092 } else {
3093 this->drawRect(r, paint);
3094 }
3095}
3096
reed@android.com8a1c16f2008-12-17 15:59:43 +00003097void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3098 SkScalar sweepAngle, bool useCenter,
3099 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003100 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003101 if (oval.isEmpty() || !sweepAngle) {
3102 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003103 }
bsalomon21af9ca2016-08-25 12:29:23 -07003104 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003105}
3106
3107void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3108 const SkPath& path, SkScalar hOffset,
3109 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003110 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003111 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003112
reed@android.com8a1c16f2008-12-17 15:59:43 +00003113 matrix.setTranslate(hOffset, vOffset);
3114 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3115}
3116
reed@android.comf76bacf2009-05-13 14:00:33 +00003117///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003118
3119/**
3120 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3121 * against the playback cost of recursing into the subpicture to get at its actual ops.
3122 *
3123 * For now we pick a conservatively small value, though measurement (and other heuristics like
3124 * the type of ops contained) may justify changing this value.
3125 */
3126#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003127
reedd5fa1a42014-08-09 11:08:05 -07003128void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003129 RETURN_ON_NULL(picture);
3130
reed1c2c4412015-04-30 13:09:24 -07003131 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003132 if (matrix && matrix->isIdentity()) {
3133 matrix = nullptr;
3134 }
3135 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3136 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3137 picture->playback(this);
3138 } else {
3139 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003140 }
3141}
robertphillips9b14f262014-06-04 05:40:44 -07003142
reedd5fa1a42014-08-09 11:08:05 -07003143void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3144 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003145 if (!paint || paint->canComputeFastBounds()) {
3146 SkRect bounds = picture->cullRect();
3147 if (paint) {
3148 paint->computeFastBounds(bounds, &bounds);
3149 }
3150 if (matrix) {
3151 matrix->mapRect(&bounds);
3152 }
3153 if (this->quickReject(bounds)) {
3154 return;
3155 }
3156 }
3157
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003158 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003159 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003160}
3161
vjiaoblack95302da2016-07-21 10:25:54 -07003162#ifdef SK_EXPERIMENTAL_SHADOWING
3163void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3164 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003165 const SkPaint* paint,
3166 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003167 RETURN_ON_NULL(picture);
3168
3169 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3170
vjiaoblacke6f5d562016-08-25 06:30:23 -07003171 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003172}
3173
3174void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3175 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003176 const SkPaint* paint,
3177 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003178 if (!paint || paint->canComputeFastBounds()) {
3179 SkRect bounds = picture->cullRect();
3180 if (paint) {
3181 paint->computeFastBounds(bounds, &bounds);
3182 }
3183 if (matrix) {
3184 matrix->mapRect(&bounds);
3185 }
3186 if (this->quickReject(bounds)) {
3187 return;
3188 }
3189 }
3190
3191 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3192
vjiaoblacke6f5d562016-08-25 06:30:23 -07003193 sk_sp<SkImage> povDepthMap;
3194 sk_sp<SkImage> diffuseMap;
3195
3196 // TODO: pass the depth to the shader in vertices, or uniforms
3197 // so we don't have to render depth and color separately
vjiaoblack904527d2016-08-09 09:32:09 -07003198 for (int i = 0; i < fLights->numLights(); ++i) {
3199 // skip over ambient lights; they don't cast shadows
3200 // lights that have shadow maps do not need updating (because lights are immutable)
3201
3202 if (SkLights::Light::kAmbient_LightType == fLights->light(i).type() ||
3203 fLights->light(i).getShadowMap() != nullptr) {
3204 continue;
3205 }
3206
3207 // TODO: compute the correct size of the depth map from the light properties
3208 // TODO: maybe add a kDepth_8_SkColorType
3209 // TODO: find actual max depth of picture
3210 SkISize shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3211 fLights->light(i), 255,
3212 picture->cullRect().width(),
3213 picture->cullRect().height());
3214
3215 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3216 kBGRA_8888_SkColorType,
3217 kOpaque_SkAlphaType);
3218
3219 // Create a new surface (that matches the backend of canvas)
3220 // for each shadow map
3221 sk_sp<SkSurface> surf(this->makeSurface(info));
3222
3223 // Wrap another SPFCanvas around the surface
3224 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3225 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
vjiaoblacke6f5d562016-08-25 06:30:23 -07003226 depthMapCanvas->setShadowParams(params);
vjiaoblack904527d2016-08-09 09:32:09 -07003227
3228 // set the depth map canvas to have the light we're drawing.
3229 SkLights::Builder builder;
3230 builder.add(fLights->light(i));
3231 sk_sp<SkLights> curLight = builder.finish();
vjiaoblack904527d2016-08-09 09:32:09 -07003232 depthMapCanvas->setLights(std::move(curLight));
vjiaoblacke6f5d562016-08-25 06:30:23 -07003233
vjiaoblack904527d2016-08-09 09:32:09 -07003234 depthMapCanvas->drawPicture(picture);
vjiaoblacke6f5d562016-08-25 06:30:23 -07003235 sk_sp<SkImage> depthMap = surf->makeImageSnapshot();
vjiaoblack904527d2016-08-09 09:32:09 -07003236
vjiaoblacke6f5d562016-08-25 06:30:23 -07003237 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3238 fLights->light(i).setShadowMap(std::move(depthMap));
3239 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3240 // we blur the variance map
3241 SkPaint blurPaint;
3242 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3243 params.fShadowRadius, nullptr));
3244
3245 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3246 kBGRA_8888_SkColorType,
3247 kOpaque_SkAlphaType);
3248
3249 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3250
3251 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3252
3253 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3254 }
vjiaoblack904527d2016-08-09 09:32:09 -07003255 }
3256
vjiaoblack904527d2016-08-09 09:32:09 -07003257 // povDepthMap
3258 {
3259 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003260 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3261 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003262 sk_sp<SkLights> povLight = builder.finish();
3263
3264 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3265 picture->cullRect().height(),
3266 kBGRA_8888_SkColorType,
3267 kOpaque_SkAlphaType);
3268
3269 // Create a new surface (that matches the backend of canvas)
3270 // to create the povDepthMap
3271 sk_sp<SkSurface> surf(this->makeSurface(info));
3272
3273 // Wrap another SPFCanvas around the surface
3274 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3275 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3276
3277 // set the depth map canvas to have the light as the user's POV
3278 depthMapCanvas->setLights(std::move(povLight));
3279
3280 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003281 povDepthMap = surf->makeImageSnapshot();
3282 }
3283
3284 // diffuseMap
3285 {
3286 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3287 picture->cullRect().height(),
3288 kBGRA_8888_SkColorType,
3289 kOpaque_SkAlphaType);
3290
3291 sk_sp<SkSurface> surf(this->makeSurface(info));
3292 surf->getCanvas()->drawPicture(picture);
3293
3294 diffuseMap = surf->makeImageSnapshot();
3295 }
vjiaoblack904527d2016-08-09 09:32:09 -07003296 SkPaint shadowPaint;
3297
3298 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3299 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003300 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3301 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003302 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3303 std::move(diffuseShader),
3304 std::move(fLights),
3305 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003306 diffuseMap->height(),
3307 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003308
3309 shadowPaint.setShader(shadowShader);
3310
3311 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003312}
3313#endif
3314
reed@android.com8a1c16f2008-12-17 15:59:43 +00003315///////////////////////////////////////////////////////////////////////////////
3316///////////////////////////////////////////////////////////////////////////////
3317
reed3aafe112016-08-18 12:45:34 -07003318SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003319 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003320
3321 SkASSERT(canvas);
3322
reed3aafe112016-08-18 12:45:34 -07003323 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003324 fDone = !fImpl->next();
3325}
3326
3327SkCanvas::LayerIter::~LayerIter() {
3328 fImpl->~SkDrawIter();
3329}
3330
3331void SkCanvas::LayerIter::next() {
3332 fDone = !fImpl->next();
3333}
3334
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003335SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003336 return fImpl->getDevice();
3337}
3338
3339const SkMatrix& SkCanvas::LayerIter::matrix() const {
3340 return fImpl->getMatrix();
3341}
3342
3343const SkPaint& SkCanvas::LayerIter::paint() const {
3344 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003345 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003346 paint = &fDefaultPaint;
3347 }
3348 return *paint;
3349}
3350
reed1e7f5e72016-04-27 07:49:17 -07003351const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003352int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3353int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003354
3355///////////////////////////////////////////////////////////////////////////////
3356
fmalitac3b589a2014-06-05 12:40:07 -07003357SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003358
3359///////////////////////////////////////////////////////////////////////////////
3360
3361static bool supported_for_raster_canvas(const SkImageInfo& info) {
3362 switch (info.alphaType()) {
3363 case kPremul_SkAlphaType:
3364 case kOpaque_SkAlphaType:
3365 break;
3366 default:
3367 return false;
3368 }
3369
3370 switch (info.colorType()) {
3371 case kAlpha_8_SkColorType:
3372 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003373 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003374 break;
3375 default:
3376 return false;
3377 }
3378
3379 return true;
3380}
3381
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003382SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3383 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003384 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003385 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003386
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003387 SkBitmap bitmap;
3388 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003389 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003390 }
halcanary385fe4d2015-08-26 13:07:48 -07003391 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003392}
reedd5fa1a42014-08-09 11:08:05 -07003393
3394///////////////////////////////////////////////////////////////////////////////
3395
3396SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003397 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003398 : fCanvas(canvas)
3399 , fSaveCount(canvas->getSaveCount())
3400{
bsalomon49f085d2014-09-05 13:34:00 -07003401 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003402 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003403 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003404 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003405 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003406 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003407 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003408 canvas->save();
3409 }
mtklein6cfa73a2014-08-13 13:33:49 -07003410
bsalomon49f085d2014-09-05 13:34:00 -07003411 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003412 canvas->concat(*matrix);
3413 }
3414}
3415
3416SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3417 fCanvas->restoreToCount(fSaveCount);
3418}
reede8f30622016-03-23 18:59:25 -07003419
3420#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3421SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
3422 return this->makeSurface(info, props).release();
3423}
3424#endif