blob: ce18c0b65d9b40ed067e4c62930e6f16d5e8c758 [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,
reedde6c5312016-09-02 12:10:07 -0700218 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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245#ifdef SK_DEBUG
246 if (!fClip.isEmpty()) {
247 SkIRect deviceR;
248 deviceR.set(0, 0, width, height);
249 SkASSERT(deviceR.contains(fClip.getBounds()));
250 }
251#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000252 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253};
254
255/* This is the record we keep for each save/restore level in the stack.
256 Since a level optionally copies the matrix and/or stack, we have pointers
257 for these fields. If the value is copied for this level, the copy is
258 stored in the ...Storage field, and the pointer points to that. If the
259 value is not copied for this level, we ignore ...Storage, and just point
260 at the corresponding value in the previous level in the stack.
261*/
262class SkCanvas::MCRec {
263public:
reed1f836ee2014-07-07 07:49:34 -0700264 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700265 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266 /* If there are any layers in the stack, this points to the top-most
267 one that is at or below this level in the stack (so we know what
268 bitmap/device to draw into from this level. This value is NOT
269 reference counted, since the real owner is either our fLayer field,
270 or a previous one in a lower level.)
271 */
reed2ff1fce2014-12-11 07:07:37 -0800272 DeviceCM* fTopLayer;
273 SkRasterClip fRasterClip;
274 SkMatrix fMatrix;
275 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276
vjiaoblacke5de1302016-07-13 14:05:28 -0700277 // This is the current cumulative depth (aggregate of all done translateZ calls)
278 SkScalar fCurDrawDepth;
279
reedd9544982014-09-09 18:46:22 -0700280 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700281 fFilter = nullptr;
282 fLayer = nullptr;
283 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800284 fMatrix.reset();
285 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700286 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700287
reedd9544982014-09-09 18:46:22 -0700288 // don't bother initializing fNext
289 inc_rec();
290 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700291 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
292 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700293 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700294 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700295 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800296 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700297
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298 // don't bother initializing fNext
299 inc_rec();
300 }
301 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000302 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700303 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 dec_rec();
305 }
mtkleinfeaadee2015-04-08 11:25:48 -0700306
307 void reset(const SkIRect& bounds) {
308 SkASSERT(fLayer);
309 SkASSERT(fDeferredSaveCount == 0);
310
311 fMatrix.reset();
312 fRasterClip.setRect(bounds);
313 fLayer->reset(bounds);
314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315};
316
317class SkDrawIter : public SkDraw {
318public:
reed3aafe112016-08-18 12:45:34 -0700319 SkDrawIter(SkCanvas* canvas) {
junov@google.com4370aed2012-01-18 16:21:08 +0000320 canvas = canvas->canvasForDrawIter();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321 canvas->updateDeviceCMCache();
322
reed687fa1c2015-04-07 08:00:56 -0700323 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324 fCurrLayer = canvas->fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325 }
reed@google.com4b226022011-01-11 18:32:13 +0000326
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 bool next() {
328 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700329 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
330 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 }
332
reed@google.comf68c5e22012-02-24 16:38:58 +0000333 const DeviceCM* rec = fCurrLayer;
334 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335
336 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000337 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700339 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700340 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700341 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000343 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344
345 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700346 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000347
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348 return true;
349 }
350 return false;
351 }
reed@google.com4b226022011-01-11 18:32:13 +0000352
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000353 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700354 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000355 int getX() const { return fDevice->getOrigin().x(); }
356 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000359
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 const DeviceCM* fCurrLayer;
362 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363
364 typedef SkDraw INHERITED;
365};
366
367/////////////////////////////////////////////////////////////////////////////
368
reeddbc3cef2015-04-29 12:18:57 -0700369static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
370 return lazy->isValid() ? lazy->get() : lazy->set(orig);
371}
372
373/**
374 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700375 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700376 */
reedd053ce92016-03-22 10:17:23 -0700377static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700378 SkImageFilter* imgf = paint.getImageFilter();
379 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700380 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700381 }
382
reedd053ce92016-03-22 10:17:23 -0700383 SkColorFilter* imgCFPtr;
384 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700385 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700386 }
reedd053ce92016-03-22 10:17:23 -0700387 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700388
389 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700390 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700391 // there is no existing paint colorfilter, so we can just return the imagefilter's
392 return imgCF;
393 }
394
395 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
396 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700397 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700398}
399
senorblanco87e066e2015-10-28 11:23:36 -0700400/**
401 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
402 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
403 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
404 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
405 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
406 * conservative "effective" bounds based on the settings in the paint... with one exception. This
407 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
408 * deliberately ignored.
409 */
410static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
411 const SkRect& rawBounds,
412 SkRect* storage) {
413 SkPaint tmpUnfiltered(paint);
414 tmpUnfiltered.setImageFilter(nullptr);
415 if (tmpUnfiltered.canComputeFastBounds()) {
416 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
417 } else {
418 return rawBounds;
419 }
420}
421
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422class AutoDrawLooper {
423public:
senorblanco87e066e2015-10-28 11:23:36 -0700424 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
425 // paint. It's used to determine the size of the offscreen layer for filters.
426 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700427 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700428 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000429 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800430#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000431 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800432#else
433 fFilter = nullptr;
434#endif
reed4a8126e2014-09-22 07:29:03 -0700435 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000436 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700437 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000438 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000439
reedd053ce92016-03-22 10:17:23 -0700440 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700441 if (simplifiedCF) {
442 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700443 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700444 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700445 fPaint = paint;
446 }
447
448 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700449 /**
450 * We implement ImageFilters for a given draw by creating a layer, then applying the
451 * imagefilter to the pixels of that layer (its backing surface/image), and then
452 * we call restore() to xfer that layer to the main canvas.
453 *
454 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
455 * 2. Generate the src pixels:
456 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
457 * return (fPaint). We then draw the primitive (using srcover) into a cleared
458 * buffer/surface.
459 * 3. Restore the layer created in #1
460 * The imagefilter is passed the buffer/surface from the layer (now filled with the
461 * src pixels of the primitive). It returns a new "filtered" buffer, which we
462 * draw onto the previous layer using the xfermode from the original paint.
463 */
reed@google.com8926b162012-03-23 15:36:36 +0000464 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700465 tmp.setImageFilter(fPaint->getImageFilter());
reedcfb6bdf2016-03-29 11:32:50 -0700466 tmp.setXfermode(sk_ref_sp(fPaint->getXfermode()));
senorblanco87e066e2015-10-28 11:23:36 -0700467 SkRect storage;
468 if (rawBounds) {
469 // Make rawBounds include all paint outsets except for those due to image filters.
470 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
471 }
reedbfd5f172016-01-07 11:28:08 -0800472 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700473 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700474 fTempLayerForImageFilter = true;
475 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000476 }
477
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000478 if (SkDrawLooper* looper = paint.getLooper()) {
479 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
480 looper->contextSize());
481 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000482 fIsSimple = false;
483 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700484 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000485 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700486 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000487 }
488 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000489
reed@android.com8a1c16f2008-12-17 15:59:43 +0000490 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700491 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000492 fCanvas->internalRestore();
493 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000494 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000495 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000496
reed@google.com4e2b3d32011-04-07 14:18:59 +0000497 const SkPaint& paint() const {
498 SkASSERT(fPaint);
499 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000500 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000501
reed@google.com129ec222012-05-15 13:24:09 +0000502 bool next(SkDrawFilter::Type drawType) {
503 if (fDone) {
504 return false;
505 } else if (fIsSimple) {
506 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000507 return !fPaint->nothingToDraw();
508 } else {
509 return this->doNext(drawType);
510 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000511 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000512
reed@android.com8a1c16f2008-12-17 15:59:43 +0000513private:
reeddbc3cef2015-04-29 12:18:57 -0700514 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
515 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000516 SkCanvas* fCanvas;
517 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000518 SkDrawFilter* fFilter;
519 const SkPaint* fPaint;
520 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700521 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000522 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000523 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000524 SkDrawLooper::Context* fLooperContext;
525 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000526
527 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528};
529
reed@google.com129ec222012-05-15 13:24:09 +0000530bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700531 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000532 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700533 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000534
reeddbc3cef2015-04-29 12:18:57 -0700535 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
536 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000537
reed5c476fb2015-04-20 08:04:21 -0700538 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700539 paint->setImageFilter(nullptr);
540 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000541 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000542
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000543 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000544 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000545 return false;
546 }
547 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000548 if (!fFilter->filter(paint, drawType)) {
549 fDone = true;
550 return false;
551 }
halcanary96fcdcc2015-08-27 07:41:13 -0700552 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000553 // no looper means we only draw once
554 fDone = true;
555 }
556 }
557 fPaint = paint;
558
559 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000560 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000561 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000562 }
563
564 // call this after any possible paint modifiers
565 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700566 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000567 return false;
568 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000569 return true;
570}
571
reed@android.com8a1c16f2008-12-17 15:59:43 +0000572////////// macros to place around the internal draw calls //////////////////
573
reed3aafe112016-08-18 12:45:34 -0700574#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
575 this->predrawNotify(); \
576 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
577 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800578 SkDrawIter iter(this);
579
580
reed@google.com8926b162012-03-23 15:36:36 +0000581#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000582 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700583 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000584 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000585 SkDrawIter iter(this);
586
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000587#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000588 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700589 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000590 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000591 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000592
reedc83a2972015-07-16 07:40:45 -0700593#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
594 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700595 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700596 while (looper.next(type)) { \
597 SkDrawIter iter(this);
598
reed@google.com4e2b3d32011-04-07 14:18:59 +0000599#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000600
601////////////////////////////////////////////////////////////////////////////
602
msarettfbfa2582016-08-12 08:29:08 -0700603static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
604 if (bounds.isEmpty()) {
605 return SkRect::MakeEmpty();
606 }
607
608 // Expand bounds out by 1 in case we are anti-aliasing. We store the
609 // bounds as floats to enable a faster quick reject implementation.
610 SkRect dst;
611 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
612 return dst;
613}
614
mtkleinfeaadee2015-04-08 11:25:48 -0700615void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
616 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700617 fClipStack->reset();
618 fMCRec->reset(bounds);
619
620 // We're peering through a lot of structs here. Only at this scope do we
621 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
622 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700623 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700624 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700625}
626
reedd9544982014-09-09 18:46:22 -0700627SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800628 if (device && device->forceConservativeRasterClip()) {
629 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
630 }
631 // Since init() is only called once by our constructors, it is safe to perform this
632 // const-cast.
633 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
634
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000635 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000636 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700637 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800638 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700639 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700640#ifdef SK_EXPERIMENTAL_SHADOWING
641 fLights = nullptr;
642#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643
halcanary385fe4d2015-08-26 13:07:48 -0700644 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700645
reed@android.com8a1c16f2008-12-17 15:59:43 +0000646 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700647 new (fMCRec) MCRec(fConservativeRasterClip);
msarett9637ea92016-08-18 14:03:30 -0700648 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649
reeda499f902015-05-01 09:34:31 -0700650 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
651 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700652 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700653 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700654
reed@android.com8a1c16f2008-12-17 15:59:43 +0000655 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656
halcanary96fcdcc2015-08-27 07:41:13 -0700657 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000658
reedf92c8662014-08-18 08:02:43 -0700659 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700660 // The root device and the canvas should always have the same pixel geometry
661 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700662 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800663 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700664 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700665 }
msarettfbfa2582016-08-12 08:29:08 -0700666
reedf92c8662014-08-18 08:02:43 -0700667 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668}
669
reed@google.comcde92112011-07-06 20:00:52 +0000670SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000671 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700672 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800673 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000674{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000675 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000676
halcanary96fcdcc2015-08-27 07:41:13 -0700677 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000678}
679
reedd9544982014-09-09 18:46:22 -0700680static SkBitmap make_nopixels(int width, int height) {
681 SkBitmap bitmap;
682 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
683 return bitmap;
684}
685
686class SkNoPixelsBitmapDevice : public SkBitmapDevice {
687public:
robertphillipsfcf78292015-06-19 11:49:52 -0700688 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
689 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800690 {
691 this->setOrigin(bounds.x(), bounds.y());
692 }
reedd9544982014-09-09 18:46:22 -0700693
694private:
piotaixrb5fae932014-09-24 13:03:30 -0700695
reedd9544982014-09-09 18:46:22 -0700696 typedef SkBitmapDevice INHERITED;
697};
698
reed96a857e2015-01-25 10:33:58 -0800699SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000700 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800701 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800702 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000703{
704 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700705
halcanary385fe4d2015-08-26 13:07:48 -0700706 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
707 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700708}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000709
reed78e27682014-11-19 08:04:34 -0800710SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700711 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700712 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800713 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700714{
715 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700716
halcanary385fe4d2015-08-26 13:07:48 -0700717 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700718}
719
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000720SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000721 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700722 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800723 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000724{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000725 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700726
reedd9544982014-09-09 18:46:22 -0700727 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000728}
729
robertphillipsfcf78292015-06-19 11:49:52 -0700730SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
731 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700732 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800733 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700734{
735 inc_canvas();
736
737 this->init(device, flags);
738}
739
reed4a8126e2014-09-22 07:29:03 -0700740SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700741 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700742 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800743 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700744{
745 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700746
halcanary385fe4d2015-08-26 13:07:48 -0700747 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700748 this->init(device, kDefault_InitFlags);
749}
reed29c857d2014-09-21 10:25:07 -0700750
reed4a8126e2014-09-22 07:29:03 -0700751SkCanvas::SkCanvas(const SkBitmap& bitmap)
752 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
753 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800754 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700755{
756 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700757
halcanary385fe4d2015-08-26 13:07:48 -0700758 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700759 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000760}
761
762SkCanvas::~SkCanvas() {
763 // free up the contents of our deque
764 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000765
reed@android.com8a1c16f2008-12-17 15:59:43 +0000766 this->internalRestore(); // restore the last, since we're going away
767
halcanary385fe4d2015-08-26 13:07:48 -0700768 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000769
reed@android.com8a1c16f2008-12-17 15:59:43 +0000770 dec_canvas();
771}
772
fmalita53d9f1c2016-01-25 06:23:54 -0800773#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000774SkDrawFilter* SkCanvas::getDrawFilter() const {
775 return fMCRec->fFilter;
776}
777
778SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700779 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000780 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
781 return filter;
782}
fmalita77650002016-01-21 18:47:11 -0800783#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000784
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000785SkMetaData& SkCanvas::getMetaData() {
786 // metadata users are rare, so we lazily allocate it. If that changes we
787 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700788 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000789 fMetaData = new SkMetaData;
790 }
791 return *fMetaData;
792}
793
reed@android.com8a1c16f2008-12-17 15:59:43 +0000794///////////////////////////////////////////////////////////////////////////////
795
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000796void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700797 this->onFlush();
798}
799
800void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000801 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000802 if (device) {
803 device->flush();
804 }
805}
806
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000807SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000808 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000809 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
810}
811
senorblancoafc7cce2016-02-02 18:44:15 -0800812SkIRect SkCanvas::getTopLayerBounds() const {
813 SkBaseDevice* d = this->getTopDevice();
814 if (!d) {
815 return SkIRect::MakeEmpty();
816 }
817 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
818}
819
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000820SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000822 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823 SkASSERT(rec && rec->fLayer);
824 return rec->fLayer->fDevice;
825}
826
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000827SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000828 if (updateMatrixClip) {
829 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
830 }
reed@google.com9266fed2011-03-30 00:18:03 +0000831 return fMCRec->fTopLayer->fDevice;
832}
833
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000834bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700835 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000836 return false;
837 }
838
839 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700840 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700841 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000842 return false;
843 }
844 weAllocated = true;
845 }
846
reedcf01e312015-05-23 19:14:51 -0700847 SkAutoPixmapUnlock unlocker;
848 if (bitmap->requestLock(&unlocker)) {
849 const SkPixmap& pm = unlocker.pixmap();
850 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
851 return true;
852 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000853 }
854
855 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700856 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000857 }
858 return false;
859}
reed@google.com51df9e32010-12-23 19:29:18 +0000860
bsalomon@google.comc6980972011-11-02 19:57:21 +0000861bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000862 SkIRect r = srcRect;
863 const SkISize size = this->getBaseLayerSize();
864 if (!r.intersect(0, 0, size.width(), size.height())) {
865 bitmap->reset();
866 return false;
867 }
868
reed84825042014-09-02 12:50:45 -0700869 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000870 // bitmap will already be reset.
871 return false;
872 }
873 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
874 bitmap->reset();
875 return false;
876 }
877 return true;
878}
879
reed96472de2014-12-10 09:53:42 -0800880bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000881 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000882 if (!device) {
883 return false;
884 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000885 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800886
reed96472de2014-12-10 09:53:42 -0800887 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
888 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000889 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000890 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000891
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000892 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800893 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000894}
895
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000896bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700897 SkAutoPixmapUnlock unlocker;
898 if (bitmap.requestLock(&unlocker)) {
899 const SkPixmap& pm = unlocker.pixmap();
900 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000901 }
902 return false;
903}
904
905bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
906 int x, int y) {
907 switch (origInfo.colorType()) {
908 case kUnknown_SkColorType:
909 case kIndex_8_SkColorType:
910 return false;
911 default:
912 break;
913 }
halcanary96fcdcc2015-08-27 07:41:13 -0700914 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000915 return false;
916 }
917
918 const SkISize size = this->getBaseLayerSize();
919 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
920 if (!target.intersect(0, 0, size.width(), size.height())) {
921 return false;
922 }
923
924 SkBaseDevice* device = this->getDevice();
925 if (!device) {
926 return false;
927 }
928
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000929 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700930 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000931
932 // if x or y are negative, then we have to adjust pixels
933 if (x > 0) {
934 x = 0;
935 }
936 if (y > 0) {
937 y = 0;
938 }
939 // here x,y are either 0 or negative
940 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
941
reed4af35f32014-06-27 17:47:49 -0700942 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700943 const bool completeOverwrite = info.dimensions() == size;
944 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700945
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000946 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000947 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000948}
reed@google.com51df9e32010-12-23 19:29:18 +0000949
junov@google.com4370aed2012-01-18 16:21:08 +0000950SkCanvas* SkCanvas::canvasForDrawIter() {
951 return this;
952}
953
reed@android.com8a1c16f2008-12-17 15:59:43 +0000954//////////////////////////////////////////////////////////////////////////////
955
reed@android.com8a1c16f2008-12-17 15:59:43 +0000956void SkCanvas::updateDeviceCMCache() {
957 if (fDeviceCMDirty) {
958 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700959 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000961
halcanary96fcdcc2015-08-27 07:41:13 -0700962 if (nullptr == layer->fNext) { // only one layer
reedde6c5312016-09-02 12:10:07 -0700963 layer->updateMC(totalMatrix, totalClip, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000965 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966 do {
reedde6c5312016-09-02 12:10:07 -0700967 layer->updateMC(totalMatrix, clip, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700968 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000969 }
970 fDeviceCMDirty = false;
971 }
972}
973
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974///////////////////////////////////////////////////////////////////////////////
975
reed2ff1fce2014-12-11 07:07:37 -0800976void SkCanvas::checkForDeferredSave() {
977 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800978 this->doSave();
979 }
980}
981
reedf0090cb2014-11-26 08:55:51 -0800982int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800983#ifdef SK_DEBUG
984 int count = 0;
985 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
986 for (;;) {
987 const MCRec* rec = (const MCRec*)iter.next();
988 if (!rec) {
989 break;
990 }
991 count += 1 + rec->fDeferredSaveCount;
992 }
993 SkASSERT(count == fSaveCount);
994#endif
995 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800996}
997
998int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800999 fSaveCount += 1;
1000 fMCRec->fDeferredSaveCount += 1;
1001 return this->getSaveCount() - 1; // return our prev value
1002}
1003
1004void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001005 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001006
1007 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1008 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001009 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001010}
1011
1012void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001013 if (fMCRec->fDeferredSaveCount > 0) {
1014 SkASSERT(fSaveCount > 1);
1015 fSaveCount -= 1;
1016 fMCRec->fDeferredSaveCount -= 1;
1017 } else {
1018 // check for underflow
1019 if (fMCStack.count() > 1) {
1020 this->willRestore();
1021 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001022 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001023 this->internalRestore();
1024 this->didRestore();
1025 }
reedf0090cb2014-11-26 08:55:51 -08001026 }
1027}
1028
1029void SkCanvas::restoreToCount(int count) {
1030 // sanity check
1031 if (count < 1) {
1032 count = 1;
1033 }
mtkleinf0f14112014-12-12 08:46:25 -08001034
reedf0090cb2014-11-26 08:55:51 -08001035 int n = this->getSaveCount() - count;
1036 for (int i = 0; i < n; ++i) {
1037 this->restore();
1038 }
1039}
1040
reed2ff1fce2014-12-11 07:07:37 -08001041void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001042 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001043 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001044 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001045
reed687fa1c2015-04-07 08:00:56 -07001046 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001047}
1048
reed4960eee2015-12-18 07:09:18 -08001049bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001050#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001051 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@google.comb93ba452014-03-10 19:47:58 +00001052#else
1053 return true;
1054#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001055}
1056
reed4960eee2015-12-18 07:09:18 -08001057bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001058 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001059 SkIRect clipBounds;
1060 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001061 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001062 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001063
reed96e657d2015-03-10 17:30:07 -07001064 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1065
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001066 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001067 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001068 if (bounds && !imageFilter->canComputeFastBounds()) {
1069 bounds = nullptr;
1070 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001071 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001072 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001073 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001074 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001075
reed96e657d2015-03-10 17:30:07 -07001076 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001077 r.roundOut(&ir);
1078 // early exit if the layer's bounds are clipped out
1079 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001080 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001081 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001082 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001083 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001084 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001085 }
1086 } else { // no user bounds, so just use the clip
1087 ir = clipBounds;
1088 }
reed180aec42015-03-11 10:39:04 -07001089 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090
reed4960eee2015-12-18 07:09:18 -08001091 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001092 // Simplify the current clips since they will be applied properly during restore()
reed687fa1c2015-04-07 08:00:56 -07001093 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001094 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001095 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001096 }
1097
1098 if (intersection) {
1099 *intersection = ir;
1100 }
1101 return true;
1102}
1103
reed4960eee2015-12-18 07:09:18 -08001104
reed4960eee2015-12-18 07:09:18 -08001105int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1106 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001107}
1108
reed70ee31b2015-12-10 13:44:45 -08001109int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001110 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1111}
1112
1113int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1114 SaveLayerRec rec(origRec);
1115 if (gIgnoreSaveLayerBounds) {
1116 rec.fBounds = nullptr;
1117 }
1118 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1119 fSaveCount += 1;
1120 this->internalSaveLayer(rec, strategy);
1121 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001122}
1123
reeda2217ef2016-07-20 06:04:34 -07001124void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1125 SkBaseDevice* dst, const SkMatrix& ctm,
1126 const SkClipStack* clipStack) {
1127 SkDraw draw;
1128 SkRasterClip rc;
1129 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1130 if (!dst->accessPixels(&draw.fDst)) {
1131 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001132 }
reeda2217ef2016-07-20 06:04:34 -07001133 draw.fMatrix = &SkMatrix::I();
1134 draw.fRC = &rc;
1135 draw.fClipStack = clipStack;
1136 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001137
1138 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001139 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001140
1141 int x = src->getOrigin().x() - dst->getOrigin().x();
1142 int y = src->getOrigin().y() - dst->getOrigin().y();
1143 auto special = src->snapSpecial();
1144 if (special) {
1145 dst->drawSpecial(draw, special.get(), x, y, p);
1146 }
robertphillips7354a4b2015-12-16 05:08:27 -08001147}
reed70ee31b2015-12-10 13:44:45 -08001148
reed129ed1c2016-02-22 06:42:31 -08001149static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1150 const SkPaint* paint) {
1151 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1152 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001153 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001154 const bool hasImageFilter = paint && paint->getImageFilter();
1155
1156 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1157 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1158 // force to L32
1159 return SkImageInfo::MakeN32(w, h, alphaType);
1160 } else {
1161 // keep the same characteristics as the prev
brianosman52ede1d2016-06-20 08:25:02 -07001162 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace()));
reed129ed1c2016-02-22 06:42:31 -08001163 }
1164}
1165
reed4960eee2015-12-18 07:09:18 -08001166void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1167 const SkRect* bounds = rec.fBounds;
1168 const SkPaint* paint = rec.fPaint;
1169 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1170
reed@google.comb93ba452014-03-10 19:47:58 +00001171#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001172 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001173#endif
1174
reed8c30a812016-04-20 16:36:51 -07001175 SkLazyPaint lazyP;
1176 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1177 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001178 SkMatrix remainder;
1179 SkSize scale;
1180 /*
1181 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1182 * but they do handle scaling. To accommodate this, we do the following:
1183 *
1184 * 1. Stash off the current CTM
1185 * 2. Decompose the CTM into SCALE and REMAINDER
1186 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1187 * contains the REMAINDER
1188 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1189 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1190 * of the original imagefilter, and draw that (via drawSprite)
1191 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1192 *
1193 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1194 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1195 */
reed96a04f32016-04-25 09:25:15 -07001196 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001197 stashedMatrix.decomposeScale(&scale, &remainder))
1198 {
1199 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1200 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1201 SkPaint* p = lazyP.set(*paint);
1202 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1203 SkFilterQuality::kLow_SkFilterQuality,
1204 sk_ref_sp(imageFilter)));
1205 imageFilter = p->getImageFilter();
1206 paint = p;
1207 }
reed8c30a812016-04-20 16:36:51 -07001208
junov@chromium.orga907ac32012-02-24 21:54:07 +00001209 // do this before we create the layer. We don't call the public save() since
1210 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001211 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001212
1213 fDeviceCMDirty = true;
1214
1215 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001216 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001217 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218 }
1219
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001220 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1221 // the clipRectBounds() call above?
1222 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001223 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001224 }
1225
reed4960eee2015-12-18 07:09:18 -08001226 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001227 SkPixelGeometry geo = fProps.pixelGeometry();
1228 if (paint) {
reed76033be2015-03-14 10:54:31 -07001229 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001230 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001231 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001232 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001233 }
1234 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001235
robertphillips5139e502016-07-19 05:10:40 -07001236 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001237 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001238 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001239 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001240 }
reedb2db8982014-11-13 12:41:02 -08001241
robertphillips5139e502016-07-19 05:10:40 -07001242 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001243 paint);
1244
robertphillips5139e502016-07-19 05:10:40 -07001245 SkAutoTUnref<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001246 {
reed70ee31b2015-12-10 13:44:45 -08001247 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001248 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001249 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001250 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
reedcd4051e2016-07-15 09:41:26 -07001251 preserveLCDText);
robertphillips5139e502016-07-19 05:10:40 -07001252 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1253 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001254 SkErrorInternals::SetError(kInternalError_SkError,
1255 "Unable to create device for layer.");
1256 return;
reed61f501f2015-04-29 08:34:00 -07001257 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001258 }
robertphillips5139e502016-07-19 05:10:40 -07001259 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001260
robertphillips5139e502016-07-19 05:10:40 -07001261 DeviceCM* layer = new DeviceCM(newDevice, paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001262
1263 layer->fNext = fMCRec->fTopLayer;
1264 fMCRec->fLayer = layer;
1265 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001266
1267 if (rec.fBackdrop) {
1268 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice,
1269 fMCRec->fMatrix, this->getClipStack());
1270 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271}
1272
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001273int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001274 if (0xFF == alpha) {
1275 return this->saveLayer(bounds, nullptr);
1276 } else {
1277 SkPaint tmpPaint;
1278 tmpPaint.setAlpha(alpha);
1279 return this->saveLayer(bounds, &tmpPaint);
1280 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001281}
1282
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283void SkCanvas::internalRestore() {
1284 SkASSERT(fMCStack.count() != 0);
1285
1286 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001287
reed687fa1c2015-04-07 08:00:56 -07001288 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001289
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001290 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291 DeviceCM* layer = fMCRec->fLayer; // may be null
1292 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001293 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294
1295 // now do the normal restore()
1296 fMCRec->~MCRec(); // balanced in save()
1297 fMCStack.pop_back();
1298 fMCRec = (MCRec*)fMCStack.back();
1299
1300 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1301 since if we're being recorded, we don't want to record this (the
1302 recorder will have already recorded the restore).
1303 */
bsalomon49f085d2014-09-05 13:34:00 -07001304 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001306 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001307 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001308 // restore what we smashed in internalSaveLayer
1309 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001310 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001312 delete layer;
reedb679ca82015-04-07 04:40:48 -07001313 } else {
1314 // we're at the root
reeda499f902015-05-01 09:34:31 -07001315 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001316 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001317 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001319 }
msarettfbfa2582016-08-12 08:29:08 -07001320
1321 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001322 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001323 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1324 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001325}
1326
reede8f30622016-03-23 18:59:25 -07001327sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001328 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001329 props = &fProps;
1330 }
1331 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001332}
1333
reede8f30622016-03-23 18:59:25 -07001334sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001335 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001336 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001337}
1338
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001339SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001340 return this->onImageInfo();
1341}
1342
1343SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001344 SkBaseDevice* dev = this->getDevice();
1345 if (dev) {
1346 return dev->imageInfo();
1347 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001348 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001349 }
1350}
1351
brianosman898235c2016-04-06 07:38:23 -07001352bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001353 return this->onGetProps(props);
1354}
1355
1356bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001357 SkBaseDevice* dev = this->getDevice();
1358 if (dev) {
1359 if (props) {
1360 *props = fProps;
1361 }
1362 return true;
1363 } else {
1364 return false;
1365 }
1366}
1367
reed6ceeebd2016-03-09 14:26:26 -08001368#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001369const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001370 SkPixmap pmap;
reed6ceeebd2016-03-09 14:26:26 -08001371 if (this->peekPixels(&pmap)) {
1372 if (info) {
1373 *info = pmap.info();
1374 }
1375 if (rowBytes) {
1376 *rowBytes = pmap.rowBytes();
1377 }
1378 return pmap.addr();
reed884e97c2015-05-26 11:31:54 -07001379 }
reed6ceeebd2016-03-09 14:26:26 -08001380 return nullptr;
1381}
1382#endif
1383
1384bool SkCanvas::peekPixels(SkPixmap* pmap) {
1385 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001386}
1387
reed884e97c2015-05-26 11:31:54 -07001388bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001389 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001390 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001391}
1392
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001393void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001394 SkPixmap pmap;
1395 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001396 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001397 }
1398 if (info) {
1399 *info = pmap.info();
1400 }
1401 if (rowBytes) {
1402 *rowBytes = pmap.rowBytes();
1403 }
1404 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001405 *origin = this->getTopDevice(false)->getOrigin();
1406 }
reed884e97c2015-05-26 11:31:54 -07001407 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001408}
1409
reed884e97c2015-05-26 11:31:54 -07001410bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001411 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001412 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001413}
1414
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416
reed7503d602016-07-15 14:23:29 -07001417void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001419 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420 paint = &tmp;
1421 }
reed@google.com4b226022011-01-11 18:32:13 +00001422
reed@google.com8926b162012-03-23 15:36:36 +00001423 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001424
reed@android.com8a1c16f2008-12-17 15:59:43 +00001425 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001426 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001427 paint = &looper.paint();
1428 SkImageFilter* filter = paint->getImageFilter();
1429 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
senorblancof35566e2016-04-18 10:32:02 -07001430 if (filter) {
reeda2217ef2016-07-20 06:04:34 -07001431 dstDev->drawSpecial(iter, srcDev->snapSpecial().get(), pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001432 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001433 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001434 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001435 }
reeda2217ef2016-07-20 06:04:34 -07001436
reed@google.com4e2b3d32011-04-07 14:18:59 +00001437 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001438}
1439
reed32704672015-12-16 08:27:10 -08001440/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001441
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001442void SkCanvas::translate(SkScalar dx, SkScalar dy) {
mtkleincbdf0072016-08-19 09:05:27 -07001443 this->checkForDeferredSave();
1444 fDeviceCMDirty = true;
1445 fMCRec->fMatrix.preTranslate(dx,dy);
1446
1447 // Translate shouldn't affect the is-scale-translateness of the matrix.
1448 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
1449
1450 this->didTranslate(dx,dy);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001451}
1452
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001453void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001454 SkMatrix m;
1455 m.setScale(sx, sy);
1456 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001457}
1458
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001459void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001460 SkMatrix m;
1461 m.setRotate(degrees);
1462 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001463}
1464
bungeman7438bfc2016-07-12 15:01:19 -07001465void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1466 SkMatrix m;
1467 m.setRotate(degrees, px, py);
1468 this->concat(m);
1469}
1470
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001471void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001472 SkMatrix m;
1473 m.setSkew(sx, sy);
1474 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001475}
1476
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001477void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001478 if (matrix.isIdentity()) {
1479 return;
1480 }
1481
reed2ff1fce2014-12-11 07:07:37 -08001482 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001483 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001484 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001485 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001486 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001487}
1488
reed8c30a812016-04-20 16:36:51 -07001489void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001490 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001491 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001492 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001493}
1494
1495void SkCanvas::setMatrix(const SkMatrix& matrix) {
1496 this->checkForDeferredSave();
1497 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001498 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001499}
1500
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001502 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503}
1504
vjiaoblack95302da2016-07-21 10:25:54 -07001505#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001506void SkCanvas::translateZ(SkScalar z) {
1507 this->checkForDeferredSave();
1508 this->fMCRec->fCurDrawDepth += z;
1509 this->didTranslateZ(z);
1510}
1511
1512SkScalar SkCanvas::getZ() const {
1513 return this->fMCRec->fCurDrawDepth;
1514}
1515
vjiaoblack95302da2016-07-21 10:25:54 -07001516void SkCanvas::setLights(sk_sp<SkLights> lights) {
1517 this->fLights = lights;
1518}
1519
1520sk_sp<SkLights> SkCanvas::getLights() const {
1521 return this->fLights;
1522}
1523#endif
1524
reed@android.com8a1c16f2008-12-17 15:59:43 +00001525//////////////////////////////////////////////////////////////////////////////
1526
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001527void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2d1afab2016-06-29 14:33:11 -07001528 if (!fAllowSoftClip) {
1529 doAA = false;
1530 }
1531
1532#ifdef SK_SUPPORT_PRECHECK_CLIPRECT
1533 // Check if we can quick-accept the clip call (and do nothing)
1534 //
reed74467162016-06-30 08:15:35 -07001535 if (SkRegion::kIntersect_Op == op && !doAA && fMCRec->fMatrix.isScaleTranslate()) {
halcanaryc5769b22016-08-10 07:13:21 -07001536 SkRect devR;
1537 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect);
reed2d1afab2016-06-29 14:33:11 -07001538 // NOTE: this check is CTM specific, since we might round differently with a different
1539 // CTM. Thus this is only 100% reliable if there is not global CTM scale to be
1540 // applied later (i.e. if this is going into a picture).
1541 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1542#if 0
1543 SkDebugf("ignored clipRect [%g %g %g %g]\n",
1544 rect.left(), rect.top(), rect.right(), rect.bottom());
1545#endif
1546 return;
1547 }
1548 }
1549#endif
1550
reed2ff1fce2014-12-11 07:07:37 -08001551 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001552 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1553 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001554}
1555
1556void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001557#ifdef SK_ENABLE_CLIP_QUICKREJECT
1558 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001559 if (fMCRec->fRasterClip.isEmpty()) {
reed2d1afab2016-06-29 14:33:11 -07001560 return;
reed@google.comda17f752012-08-16 18:27:05 +00001561 }
1562
reed@google.com3b3e8952012-08-16 20:53:31 +00001563 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001564 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001565 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001566
reed687fa1c2015-04-07 08:00:56 -07001567 fClipStack->clipEmpty();
reed2d1afab2016-06-29 14:33:11 -07001568 (void)fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001569 fDeviceClipBounds.setEmpty();
reed2d1afab2016-06-29 14:33:11 -07001570 return;
reed@google.comda17f752012-08-16 18:27:05 +00001571 }
1572 }
1573#endif
1574
reed74467162016-06-30 08:15:35 -07001575 const bool isScaleTrans = fMCRec->fMatrix.isScaleTranslate();
reedc64eff52015-11-21 12:39:45 -08001576 SkRect devR;
reed74467162016-06-30 08:15:35 -07001577 if (isScaleTrans) {
halcanaryc5769b22016-08-10 07:13:21 -07001578 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect);
reedc64eff52015-11-21 12:39:45 -08001579 }
bsalomonac8cabd2015-11-20 18:53:07 -08001580
reed2d1afab2016-06-29 14:33:11 -07001581#ifndef SK_SUPPORT_PRECHECK_CLIPRECT
reedc64eff52015-11-21 12:39:45 -08001582 if (SkRegion::kIntersect_Op == op &&
1583 kHard_ClipEdgeStyle == edgeStyle
reed74467162016-06-30 08:15:35 -07001584 && isScaleTrans)
reedc64eff52015-11-21 12:39:45 -08001585 {
1586 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1587#if 0
1588 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1589 rect.left(), rect.top(), rect.right(), rect.bottom());
1590#endif
1591 return;
1592 }
1593 }
reed2d1afab2016-06-29 14:33:11 -07001594#endif
reedc64eff52015-11-21 12:39:45 -08001595
1596 AutoValidateClip avc(this);
1597
1598 fDeviceCMDirty = true;
reedc64eff52015-11-21 12:39:45 -08001599
reed74467162016-06-30 08:15:35 -07001600 if (isScaleTrans) {
reedc64eff52015-11-21 12:39:45 -08001601 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1602 fClipStack->clipDevRect(devR, op, isAA);
senorblancoafc7cce2016-02-02 18:44:15 -08001603 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001604 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001605 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001606 // and clip against that, since it can handle any matrix. However, to
1607 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1608 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001609 SkPath path;
1610
1611 path.addRect(rect);
bsalomonbdc335f2016-08-22 13:42:17 -07001612 path.setIsVolatile(true);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001613 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001614 }
msarettfbfa2582016-08-12 08:29:08 -07001615
1616 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001617}
1618
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001619void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001620 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001621 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001622 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001623 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1624 } else {
1625 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001626 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001627}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001628
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001629void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001630 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001631 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001632 AutoValidateClip avc(this);
1633
1634 fDeviceCMDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001635 if (!fAllowSoftClip) {
1636 edgeStyle = kHard_ClipEdgeStyle;
1637 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001638
reed687fa1c2015-04-07 08:00:56 -07001639 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001640
senorblancoafc7cce2016-02-02 18:44:15 -08001641 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
robertphillips125f19a2015-11-23 09:00:05 -08001642 kSoft_ClipEdgeStyle == edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001643 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001644 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001645 }
1646
1647 SkPath path;
1648 path.addRRect(rrect);
bsalomonbdc335f2016-08-22 13:42:17 -07001649 path.setIsVolatile(true);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001650 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001651 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001652}
1653
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001654void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001655 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001656 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001657
1658 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1659 SkRect r;
1660 if (path.isRect(&r)) {
1661 this->onClipRect(r, op, edgeStyle);
1662 return;
1663 }
1664 SkRRect rrect;
1665 if (path.isOval(&r)) {
1666 rrect.setOval(r);
1667 this->onClipRRect(rrect, op, edgeStyle);
1668 return;
1669 }
1670 if (path.isRRect(&rrect)) {
1671 this->onClipRRect(rrect, op, edgeStyle);
1672 return;
1673 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001674 }
robertphillips39f05382015-11-24 09:30:12 -08001675
1676 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001677}
1678
1679void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001680#ifdef SK_ENABLE_CLIP_QUICKREJECT
1681 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001682 if (fMCRec->fRasterClip.isEmpty()) {
reed2d1afab2016-06-29 14:33:11 -07001683 return;
reed@google.comda17f752012-08-16 18:27:05 +00001684 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001685
reed@google.com3b3e8952012-08-16 20:53:31 +00001686 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001687 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001688 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001689
reed687fa1c2015-04-07 08:00:56 -07001690 fClipStack->clipEmpty();
reed2d1afab2016-06-29 14:33:11 -07001691 (void)fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001692 fDeviceClipBounds.setEmpty();
reed2d1afab2016-06-29 14:33:11 -07001693 return;
reed@google.comda17f752012-08-16 18:27:05 +00001694 }
1695 }
1696#endif
1697
reed@google.com5c3d1472011-02-22 19:12:23 +00001698 AutoValidateClip avc(this);
1699
reed@android.com8a1c16f2008-12-17 15:59:43 +00001700 fDeviceCMDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001701 if (!fAllowSoftClip) {
1702 edgeStyle = kHard_ClipEdgeStyle;
1703 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001704
1705 SkPath devPath;
bsalomonbdc335f2016-08-22 13:42:17 -07001706 if (fMCRec->fMatrix.isIdentity()) {
1707 devPath = path;
1708 } else {
1709 path.transform(fMCRec->fMatrix, &devPath);
1710 devPath.setIsVolatile(true);
1711 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001712
reed@google.comfe701122011-11-08 19:41:23 +00001713 // Check if the transfomation, or the original path itself
1714 // made us empty. Note this can also happen if we contained NaN
1715 // values. computing the bounds detects this, and will set our
1716 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1717 if (devPath.getBounds().isEmpty()) {
1718 // resetting the path will remove any NaN or other wanky values
1719 // that might upset our scan converter.
1720 devPath.reset();
1721 }
1722
reed@google.com5c3d1472011-02-22 19:12:23 +00001723 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001724 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001725
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001726 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001727 bool clipIsAA = getClipStack()->asPath(&devPath);
1728 if (clipIsAA) {
1729 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001730 }
fmalita1a481fe2015-02-04 07:39:34 -08001731
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001732 op = SkRegion::kReplace_Op;
1733 }
1734
senorblancoafc7cce2016-02-02 18:44:15 -08001735 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001736 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001737}
1738
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001739void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001740 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001741 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001742}
1743
1744void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001745 AutoValidateClip avc(this);
1746
reed@android.com8a1c16f2008-12-17 15:59:43 +00001747 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001748
reed@google.com5c3d1472011-02-22 19:12:23 +00001749 // todo: signal fClipStack that we have a region, and therefore (I guess)
1750 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001751 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001752
reed1f836ee2014-07-07 07:49:34 -07001753 fMCRec->fRasterClip.op(rgn, op);
msarettfbfa2582016-08-12 08:29:08 -07001754 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001755}
1756
reed@google.com819c9212011-02-23 18:56:55 +00001757#ifdef SK_DEBUG
1758void SkCanvas::validateClip() const {
1759 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001760 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001761 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001762 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001763 return;
1764 }
1765
reed@google.com819c9212011-02-23 18:56:55 +00001766 SkIRect ir;
1767 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001768 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001769
reed687fa1c2015-04-07 08:00:56 -07001770 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001771 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001772 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001773 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001774 case SkClipStack::Element::kRect_Type:
1775 element->getRect().round(&ir);
1776 tmpClip.op(ir, element->getOp());
1777 break;
1778 case SkClipStack::Element::kEmpty_Type:
1779 tmpClip.setEmpty();
1780 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001781 default: {
1782 SkPath path;
1783 element->asPath(&path);
senorblancoafc7cce2016-02-02 18:44:15 -08001784 tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001785 break;
1786 }
reed@google.com819c9212011-02-23 18:56:55 +00001787 }
1788 }
reed@google.com819c9212011-02-23 18:56:55 +00001789}
1790#endif
1791
reed@google.com90c07ea2012-04-13 13:50:27 +00001792void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001793 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001794 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001795
halcanary96fcdcc2015-08-27 07:41:13 -07001796 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001797 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001798 }
1799}
1800
reed@google.com5c3d1472011-02-22 19:12:23 +00001801///////////////////////////////////////////////////////////////////////////////
1802
reed@google.com754de5f2014-02-24 19:38:20 +00001803bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001804 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001805}
1806
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001807bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001808 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001809}
1810
msarettfbfa2582016-08-12 08:29:08 -07001811static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1812#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1813 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1814 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1815 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1816 return 0xF != _mm_movemask_ps(mask);
1817#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1818 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1819 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1820 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1821 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1822#else
1823 SkRect devRectAsRect;
1824 SkRect devClipAsRect;
1825 devRect.store(&devRectAsRect.fLeft);
1826 devClip.store(&devClipAsRect.fLeft);
1827 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1828#endif
1829}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001830
msarettfbfa2582016-08-12 08:29:08 -07001831// It's important for this function to not be inlined. Otherwise the compiler will share code
1832// between the fast path and the slow path, resulting in two slow paths.
1833static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1834 const SkMatrix& matrix) {
1835 SkRect deviceRect;
1836 matrix.mapRect(&deviceRect, src);
1837 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1838}
1839
1840bool SkCanvas::quickReject(const SkRect& src) const {
1841#ifdef SK_DEBUG
1842 // Verify that fDeviceClipBounds are set properly.
1843 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001844 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001845 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001846 } else {
msarettfbfa2582016-08-12 08:29:08 -07001847 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001848 }
msarettfbfa2582016-08-12 08:29:08 -07001849
msarett9637ea92016-08-18 14:03:30 -07001850 // Verify that fIsScaleTranslate is set properly.
1851 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001852#endif
1853
msarett9637ea92016-08-18 14:03:30 -07001854 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001855 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1856 }
1857
1858 // We inline the implementation of mapScaleTranslate() for the fast path.
1859 float sx = fMCRec->fMatrix.getScaleX();
1860 float sy = fMCRec->fMatrix.getScaleY();
1861 float tx = fMCRec->fMatrix.getTranslateX();
1862 float ty = fMCRec->fMatrix.getTranslateY();
1863 Sk4f scale(sx, sy, sx, sy);
1864 Sk4f trans(tx, ty, tx, ty);
1865
1866 // Apply matrix.
1867 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1868
1869 // Make sure left < right, top < bottom.
1870 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1871 Sk4f min = Sk4f::Min(ltrb, rblt);
1872 Sk4f max = Sk4f::Max(ltrb, rblt);
1873 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1874 // ARM this sequence generates the fastest (a single instruction).
1875 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1876
1877 // Check if the device rect is NaN or outside the clip.
1878 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001879}
1880
reed@google.com3b3e8952012-08-16 20:53:31 +00001881bool SkCanvas::quickReject(const SkPath& path) const {
1882 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001883}
1884
reed@google.com3b3e8952012-08-16 20:53:31 +00001885bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001886 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001887 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001888 return false;
1889 }
1890
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001891 SkMatrix inverse;
1892 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001893 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001894 if (bounds) {
1895 bounds->setEmpty();
1896 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001897 return false;
1898 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001899
bsalomon49f085d2014-09-05 13:34:00 -07001900 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001901 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001902 // adjust it outwards in case we are antialiasing
1903 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001904
reed@google.com8f4d2302013-12-17 16:44:46 +00001905 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1906 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001907 inverse.mapRect(bounds, r);
1908 }
1909 return true;
1910}
1911
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001912bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001913 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001914 if (clip.isEmpty()) {
1915 if (bounds) {
1916 bounds->setEmpty();
1917 }
1918 return false;
1919 }
1920
bsalomon49f085d2014-09-05 13:34:00 -07001921 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001922 *bounds = clip.getBounds();
1923 }
1924 return true;
1925}
1926
reed@android.com8a1c16f2008-12-17 15:59:43 +00001927const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001928 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001929}
1930
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001931const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001932 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001933}
1934
robertphillips175dd9b2016-04-28 14:32:04 -07001935GrDrawContext* SkCanvas::internal_private_accessTopLayerDrawContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001936 SkBaseDevice* dev = this->getTopDevice();
robertphillips175dd9b2016-04-28 14:32:04 -07001937 return dev ? dev->accessDrawContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001938}
1939
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001940GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001941 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001942 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001943}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001944
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001945void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1946 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001947 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001948 if (outer.isEmpty()) {
1949 return;
1950 }
1951 if (inner.isEmpty()) {
1952 this->drawRRect(outer, paint);
1953 return;
1954 }
1955
1956 // We don't have this method (yet), but technically this is what we should
1957 // be able to assert...
1958 // SkASSERT(outer.contains(inner));
1959 //
1960 // For now at least check for containment of bounds
1961 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1962
1963 this->onDrawDRRect(outer, inner, paint);
1964}
1965
reed41af9662015-01-05 07:49:08 -08001966// These need to stop being virtual -- clients need to override the onDraw... versions
1967
1968void SkCanvas::drawPaint(const SkPaint& paint) {
1969 this->onDrawPaint(paint);
1970}
1971
1972void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1973 this->onDrawRect(r, paint);
1974}
1975
msarettdca352e2016-08-26 06:37:45 -07001976void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
1977 if (region.isEmpty()) {
1978 return;
1979 }
1980
1981 if (region.isRect()) {
1982 return this->drawIRect(region.getBounds(), paint);
1983 }
1984
1985 this->onDrawRegion(region, paint);
1986}
1987
reed41af9662015-01-05 07:49:08 -08001988void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1989 this->onDrawOval(r, paint);
1990}
1991
1992void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1993 this->onDrawRRect(rrect, paint);
1994}
1995
1996void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1997 this->onDrawPoints(mode, count, pts, paint);
1998}
1999
2000void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
2001 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
2002 const uint16_t indices[], int indexCount, const SkPaint& paint) {
2003 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
2004 indices, indexCount, paint);
2005}
2006
2007void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
2008 this->onDrawPath(path, paint);
2009}
2010
reeda85d4d02015-05-06 12:56:48 -07002011void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002012 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07002013 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08002014}
2015
reede47829b2015-08-06 10:02:53 -07002016void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
2017 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002018 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002019 if (dst.isEmpty() || src.isEmpty()) {
2020 return;
2021 }
2022 this->onDrawImageRect(image, &src, dst, paint, constraint);
2023}
reed41af9662015-01-05 07:49:08 -08002024
reed84984ef2015-07-17 07:09:43 -07002025void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
2026 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002027 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002028 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002029}
2030
reede47829b2015-08-06 10:02:53 -07002031void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
2032 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002033 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002034 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
2035 constraint);
2036}
reede47829b2015-08-06 10:02:53 -07002037
reed4c21dc52015-06-25 12:32:03 -07002038void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2039 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002040 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07002041 if (dst.isEmpty()) {
2042 return;
2043 }
msarett552bca92016-08-03 06:53:26 -07002044 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
2045 this->onDrawImageNine(image, center, dst, paint);
2046 } else {
reede47829b2015-08-06 10:02:53 -07002047 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002048 }
reed4c21dc52015-06-25 12:32:03 -07002049}
2050
msarett16882062016-08-16 09:31:08 -07002051void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2052 const SkPaint* paint) {
2053 RETURN_ON_NULL(image);
2054 if (dst.isEmpty()) {
2055 return;
2056 }
2057 if (SkLatticeIter::Valid(image->width(), image->height(), lattice)) {
2058 this->onDrawImageLattice(image, lattice, dst, paint);
2059 } else {
2060 this->drawImageRect(image, dst, paint);
2061 }
2062}
2063
reed41af9662015-01-05 07:49:08 -08002064void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002065 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002066 return;
2067 }
reed41af9662015-01-05 07:49:08 -08002068 this->onDrawBitmap(bitmap, dx, dy, paint);
2069}
2070
reede47829b2015-08-06 10:02:53 -07002071void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002072 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002073 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002074 return;
2075 }
reede47829b2015-08-06 10:02:53 -07002076 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002077}
2078
reed84984ef2015-07-17 07:09:43 -07002079void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2080 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002081 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002082}
2083
reede47829b2015-08-06 10:02:53 -07002084void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2085 SrcRectConstraint constraint) {
2086 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2087 constraint);
2088}
reede47829b2015-08-06 10:02:53 -07002089
reed41af9662015-01-05 07:49:08 -08002090void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2091 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002092 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002093 return;
2094 }
msarett552bca92016-08-03 06:53:26 -07002095 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2096 this->onDrawBitmapNine(bitmap, center, dst, paint);
2097 } else {
reeda5517e22015-07-14 10:54:12 -07002098 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002099 }
reed41af9662015-01-05 07:49:08 -08002100}
2101
msarettc573a402016-08-02 08:05:56 -07002102void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2103 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002104 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002105 return;
2106 }
msarett16882062016-08-16 09:31:08 -07002107 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), lattice)) {
2108 this->onDrawBitmapLattice(bitmap, lattice, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002109 } else {
msarett16882062016-08-16 09:31:08 -07002110 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002111 }
msarettc573a402016-08-02 08:05:56 -07002112}
2113
reed71c3c762015-06-24 10:29:17 -07002114void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2115 const SkColor colors[], int count, SkXfermode::Mode mode,
2116 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002117 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002118 if (count <= 0) {
2119 return;
2120 }
2121 SkASSERT(atlas);
2122 SkASSERT(xform);
2123 SkASSERT(tex);
2124 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2125}
2126
reedf70b5312016-03-04 16:36:20 -08002127void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2128 if (key) {
2129 this->onDrawAnnotation(rect, key, value);
2130 }
2131}
2132
reede47829b2015-08-06 10:02:53 -07002133void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2134 const SkPaint* paint, SrcRectConstraint constraint) {
2135 if (src) {
2136 this->drawImageRect(image, *src, dst, paint, constraint);
2137 } else {
2138 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2139 dst, paint, constraint);
2140 }
2141}
2142void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2143 const SkPaint* paint, SrcRectConstraint constraint) {
2144 if (src) {
2145 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2146 } else {
2147 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2148 dst, paint, constraint);
2149 }
2150}
2151
tomhudsoncb3bd182016-05-18 07:24:16 -07002152void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2153 SkIRect layer_bounds = this->getTopLayerBounds();
2154 if (matrix) {
2155 *matrix = this->getTotalMatrix();
2156 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2157 }
2158 if (clip_bounds) {
2159 this->getClipDeviceBounds(clip_bounds);
2160 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2161 }
2162}
2163
reed@android.com8a1c16f2008-12-17 15:59:43 +00002164//////////////////////////////////////////////////////////////////////////////
2165// These are the virtual drawing methods
2166//////////////////////////////////////////////////////////////////////////////
2167
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002168void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002169 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002170 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2171 }
2172}
2173
reed41af9662015-01-05 07:49:08 -08002174void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002175 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002176 this->internalDrawPaint(paint);
2177}
2178
2179void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002180 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002181
2182 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002183 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002184 }
2185
reed@google.com4e2b3d32011-04-07 14:18:59 +00002186 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002187}
2188
reed41af9662015-01-05 07:49:08 -08002189void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2190 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002191 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002192 if ((long)count <= 0) {
2193 return;
2194 }
2195
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002196 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002197 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002198 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002199 // special-case 2 points (common for drawing a single line)
2200 if (2 == count) {
2201 r.set(pts[0], pts[1]);
2202 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002203 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002204 }
senorblanco87e066e2015-10-28 11:23:36 -07002205 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2206 return;
2207 }
2208 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002209 }
reed@google.coma584aed2012-05-16 14:06:02 +00002210
halcanary96fcdcc2015-08-27 07:41:13 -07002211 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002212
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002213 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002214
reed@android.com8a1c16f2008-12-17 15:59:43 +00002215 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002216 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002217 }
reed@google.com4b226022011-01-11 18:32:13 +00002218
reed@google.com4e2b3d32011-04-07 14:18:59 +00002219 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002220}
2221
reed4a167172016-08-18 17:15:25 -07002222static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2223 return ((intptr_t)paint.getImageFilter() |
2224#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2225 (intptr_t)canvas->getDrawFilter() |
2226#endif
2227 (intptr_t)paint.getLooper() ) != 0;
2228}
2229
reed41af9662015-01-05 07:49:08 -08002230void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002231 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002232 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002233 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002234 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002235 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2236 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2237 SkRect tmp(r);
2238 tmp.sort();
2239
senorblanco87e066e2015-10-28 11:23:36 -07002240 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2241 return;
2242 }
2243 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002244 }
reed@google.com4b226022011-01-11 18:32:13 +00002245
reed4a167172016-08-18 17:15:25 -07002246 if (needs_autodrawlooper(this, paint)) {
2247 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002248
reed4a167172016-08-18 17:15:25 -07002249 while (iter.next()) {
2250 iter.fDevice->drawRect(iter, r, looper.paint());
2251 }
2252
2253 LOOPER_END
2254 } else {
2255 this->predrawNotify(bounds, &paint, false);
2256 SkDrawIter iter(this);
2257 while (iter.next()) {
2258 iter.fDevice->drawRect(iter, r, paint);
2259 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002260 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002261}
2262
msarett44df6512016-08-25 13:54:30 -07002263void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
2264 SkRect storage;
2265 SkRect regionRect = SkRect::Make(region.getBounds());
2266 const SkRect* bounds = nullptr;
2267 if (paint.canComputeFastBounds()) {
2268 if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) {
2269 return;
2270 }
2271 bounds = &regionRect;
2272 }
2273
2274 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
2275
2276 while (iter.next()) {
2277 iter.fDevice->drawRegion(iter, region, looper.paint());
2278 }
2279
2280 LOOPER_END
2281}
2282
reed41af9662015-01-05 07:49:08 -08002283void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002284 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002285 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002286 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002287 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002288 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2289 return;
2290 }
2291 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002292 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002293
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002294 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002295
2296 while (iter.next()) {
2297 iter.fDevice->drawOval(iter, oval, looper.paint());
2298 }
2299
2300 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002301}
2302
bsalomonac3aa242016-08-19 11:25:19 -07002303void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2304 SkScalar sweepAngle, bool useCenter,
2305 const SkPaint& paint) {
2306 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2307 const SkRect* bounds = nullptr;
2308 if (paint.canComputeFastBounds()) {
2309 SkRect storage;
2310 // Note we're using the entire oval as the bounds.
2311 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2312 return;
2313 }
2314 bounds = &oval;
2315 }
2316
2317 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2318
2319 while (iter.next()) {
2320 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2321 }
2322
2323 LOOPER_END
2324}
2325
reed41af9662015-01-05 07:49:08 -08002326void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002327 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002328 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002329 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002330 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002331 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2332 return;
2333 }
2334 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002335 }
2336
2337 if (rrect.isRect()) {
2338 // call the non-virtual version
2339 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002340 return;
2341 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002342 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002343 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2344 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002345 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002346
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002347 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002348
2349 while (iter.next()) {
2350 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2351 }
2352
2353 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002354}
2355
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002356void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2357 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002358 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002359 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002360 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002361 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2362 return;
2363 }
2364 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002365 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002366
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002367 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002368
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002369 while (iter.next()) {
2370 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2371 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002372
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002373 LOOPER_END
2374}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002375
reed41af9662015-01-05 07:49:08 -08002376void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002377 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002378 if (!path.isFinite()) {
2379 return;
2380 }
2381
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002382 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002383 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002384 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002385 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002386 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2387 return;
2388 }
2389 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002390 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002391
2392 const SkRect& r = path.getBounds();
2393 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002394 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002395 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002396 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002397 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002398 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002399
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002400 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002401
2402 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002403 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002404 }
2405
reed@google.com4e2b3d32011-04-07 14:18:59 +00002406 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002407}
2408
reed262a71b2015-12-05 13:07:27 -08002409bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002410 if (!paint.getImageFilter()) {
2411 return false;
2412 }
2413
2414 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002415 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002416 return false;
2417 }
2418
2419 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2420 // Once we can filter and the filter will return a result larger than itself, we should be
2421 // able to remove this constraint.
2422 // skbug.com/4526
2423 //
2424 SkPoint pt;
2425 ctm.mapXY(x, y, &pt);
2426 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2427 return ir.contains(fMCRec->fRasterClip.getBounds());
2428}
2429
reeda85d4d02015-05-06 12:56:48 -07002430void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002431 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002432 SkRect bounds = SkRect::MakeXYWH(x, y,
2433 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002434 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002435 SkRect tmp = bounds;
2436 if (paint) {
2437 paint->computeFastBounds(tmp, &tmp);
2438 }
2439 if (this->quickReject(tmp)) {
2440 return;
2441 }
reeda85d4d02015-05-06 12:56:48 -07002442 }
halcanary9d524f22016-03-29 09:03:52 -07002443
reeda85d4d02015-05-06 12:56:48 -07002444 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002445 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002446 paint = lazy.init();
2447 }
reed262a71b2015-12-05 13:07:27 -08002448
reeda2217ef2016-07-20 06:04:34 -07002449 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002450 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2451 *paint);
2452 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002453 special = this->getDevice()->makeSpecial(image);
2454 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002455 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002456 }
2457 }
2458
reed262a71b2015-12-05 13:07:27 -08002459 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2460
reeda85d4d02015-05-06 12:56:48 -07002461 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002462 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002463 if (special) {
2464 SkPoint pt;
2465 iter.fMatrix->mapXY(x, y, &pt);
2466 iter.fDevice->drawSpecial(iter, special.get(),
2467 SkScalarRoundToInt(pt.fX),
2468 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002469 } else {
2470 iter.fDevice->drawImage(iter, image, x, y, pnt);
2471 }
reeda85d4d02015-05-06 12:56:48 -07002472 }
halcanary9d524f22016-03-29 09:03:52 -07002473
reeda85d4d02015-05-06 12:56:48 -07002474 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002475}
2476
reed41af9662015-01-05 07:49:08 -08002477void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002478 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002479 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002480 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002481 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002482 if (paint) {
2483 paint->computeFastBounds(dst, &storage);
2484 }
2485 if (this->quickReject(storage)) {
2486 return;
2487 }
reeda85d4d02015-05-06 12:56:48 -07002488 }
2489 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002490 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002491 paint = lazy.init();
2492 }
halcanary9d524f22016-03-29 09:03:52 -07002493
senorblancoc41e7e12015-12-07 12:51:30 -08002494 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002495 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002496
reeda85d4d02015-05-06 12:56:48 -07002497 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002498 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002499 }
halcanary9d524f22016-03-29 09:03:52 -07002500
reeda85d4d02015-05-06 12:56:48 -07002501 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002502}
2503
reed41af9662015-01-05 07:49:08 -08002504void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002505 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002506 SkDEBUGCODE(bitmap.validate();)
2507
reed33366972015-10-08 09:22:02 -07002508 if (bitmap.drawsNothing()) {
2509 return;
2510 }
2511
2512 SkLazyPaint lazy;
2513 if (nullptr == paint) {
2514 paint = lazy.init();
2515 }
2516
2517 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2518
2519 SkRect storage;
2520 const SkRect* bounds = nullptr;
2521 if (paint->canComputeFastBounds()) {
2522 bitmap.getBounds(&storage);
2523 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002524 SkRect tmp = storage;
2525 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2526 return;
2527 }
2528 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002529 }
reed@google.com4b226022011-01-11 18:32:13 +00002530
reeda2217ef2016-07-20 06:04:34 -07002531 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002532 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2533 *paint);
2534 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002535 special = this->getDevice()->makeSpecial(bitmap);
2536 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002537 drawAsSprite = false;
2538 }
2539 }
2540
reed262a71b2015-12-05 13:07:27 -08002541 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002542
2543 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002544 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002545 if (special) {
reed262a71b2015-12-05 13:07:27 -08002546 SkPoint pt;
2547 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002548 iter.fDevice->drawSpecial(iter, special.get(),
2549 SkScalarRoundToInt(pt.fX),
2550 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002551 } else {
2552 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2553 }
reed33366972015-10-08 09:22:02 -07002554 }
msarettfbfa2582016-08-12 08:29:08 -07002555
reed33366972015-10-08 09:22:02 -07002556 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002557}
2558
reed@google.com9987ec32011-09-07 11:57:52 +00002559// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002560void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002561 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002562 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002563 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002564 return;
2565 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002566
halcanary96fcdcc2015-08-27 07:41:13 -07002567 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002568 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002569 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2570 return;
2571 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002572 }
reed@google.com3d608122011-11-21 15:16:16 +00002573
reed@google.com33535f32012-09-25 15:37:50 +00002574 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002575 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002576 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002577 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002578
senorblancoc41e7e12015-12-07 12:51:30 -08002579 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002580 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002581
reed@google.com33535f32012-09-25 15:37:50 +00002582 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002583 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002584 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002585
reed@google.com33535f32012-09-25 15:37:50 +00002586 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002587}
2588
reed41af9662015-01-05 07:49:08 -08002589void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002590 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002591 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002592 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002593 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002594}
2595
reed4c21dc52015-06-25 12:32:03 -07002596void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2597 const SkPaint* paint) {
2598 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002599
halcanary96fcdcc2015-08-27 07:41:13 -07002600 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002601 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002602 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2603 return;
2604 }
reed@google.com3d608122011-11-21 15:16:16 +00002605 }
halcanary9d524f22016-03-29 09:03:52 -07002606
reed4c21dc52015-06-25 12:32:03 -07002607 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002608 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002609 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002610 }
halcanary9d524f22016-03-29 09:03:52 -07002611
senorblancoc41e7e12015-12-07 12:51:30 -08002612 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002613
reed4c21dc52015-06-25 12:32:03 -07002614 while (iter.next()) {
2615 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002616 }
halcanary9d524f22016-03-29 09:03:52 -07002617
reed4c21dc52015-06-25 12:32:03 -07002618 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002619}
2620
reed41af9662015-01-05 07:49:08 -08002621void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2622 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002623 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002624 SkDEBUGCODE(bitmap.validate();)
2625
halcanary96fcdcc2015-08-27 07:41:13 -07002626 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002627 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002628 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2629 return;
2630 }
reed4c21dc52015-06-25 12:32:03 -07002631 }
halcanary9d524f22016-03-29 09:03:52 -07002632
reed4c21dc52015-06-25 12:32:03 -07002633 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002634 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002635 paint = lazy.init();
2636 }
halcanary9d524f22016-03-29 09:03:52 -07002637
senorblancoc41e7e12015-12-07 12:51:30 -08002638 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002639
reed4c21dc52015-06-25 12:32:03 -07002640 while (iter.next()) {
2641 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2642 }
halcanary9d524f22016-03-29 09:03:52 -07002643
reed4c21dc52015-06-25 12:32:03 -07002644 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002645}
2646
msarett16882062016-08-16 09:31:08 -07002647void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2648 const SkPaint* paint) {
2649 if (nullptr == paint || paint->canComputeFastBounds()) {
2650 SkRect storage;
2651 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2652 return;
2653 }
2654 }
2655
2656 SkLazyPaint lazy;
2657 if (nullptr == paint) {
2658 paint = lazy.init();
2659 }
2660
2661 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2662
2663 while (iter.next()) {
2664 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2665 }
2666
2667 LOOPER_END
2668}
2669
2670void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2671 const SkRect& dst, const SkPaint* paint) {
2672 if (nullptr == paint || paint->canComputeFastBounds()) {
2673 SkRect storage;
2674 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2675 return;
2676 }
2677 }
2678
2679 SkLazyPaint lazy;
2680 if (nullptr == paint) {
2681 paint = lazy.init();
2682 }
2683
2684 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2685
2686 while (iter.next()) {
2687 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2688 }
2689
2690 LOOPER_END
2691}
2692
reed@google.comf67e4cf2011-03-15 20:56:58 +00002693class SkDeviceFilteredPaint {
2694public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002695 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002696 uint32_t filteredFlags = device->filterTextFlags(paint);
2697 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002698 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002699 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002700 fPaint = newPaint;
2701 } else {
2702 fPaint = &paint;
2703 }
2704 }
2705
reed@google.comf67e4cf2011-03-15 20:56:58 +00002706 const SkPaint& paint() const { return *fPaint; }
2707
2708private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002709 const SkPaint* fPaint;
2710 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002711};
2712
bungeman@google.com52c748b2011-08-22 21:30:43 +00002713void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2714 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002715 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002716 draw.fDevice->drawRect(draw, r, paint);
2717 } else {
2718 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002719 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002720 draw.fDevice->drawRect(draw, r, p);
2721 }
2722}
2723
2724void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2725 const char text[], size_t byteLength,
2726 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002727 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002728
2729 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002730 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002731 draw.fRC->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002732 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002733 return;
2734 }
2735
2736 SkScalar width = 0;
2737 SkPoint start;
2738
2739 start.set(0, 0); // to avoid warning
2740 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2741 SkPaint::kStrikeThruText_Flag)) {
2742 width = paint.measureText(text, byteLength);
2743
2744 SkScalar offsetX = 0;
2745 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2746 offsetX = SkScalarHalf(width);
2747 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2748 offsetX = width;
2749 }
2750 start.set(x - offsetX, y);
2751 }
2752
2753 if (0 == width) {
2754 return;
2755 }
2756
2757 uint32_t flags = paint.getFlags();
2758
2759 if (flags & (SkPaint::kUnderlineText_Flag |
2760 SkPaint::kStrikeThruText_Flag)) {
2761 SkScalar textSize = paint.getTextSize();
2762 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2763 SkRect r;
2764
2765 r.fLeft = start.fX;
2766 r.fRight = start.fX + width;
2767
2768 if (flags & SkPaint::kUnderlineText_Flag) {
2769 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2770 start.fY);
2771 r.fTop = offset;
2772 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002773 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002774 }
2775 if (flags & SkPaint::kStrikeThruText_Flag) {
2776 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2777 start.fY);
2778 r.fTop = offset;
2779 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002780 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002781 }
2782 }
2783}
2784
reed@google.come0d9ce82014-04-23 04:00:17 +00002785void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2786 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002787 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002788
2789 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002790 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002791 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002792 DrawTextDecorations(iter, dfp.paint(),
2793 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002794 }
2795
reed@google.com4e2b3d32011-04-07 14:18:59 +00002796 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002797}
2798
reed@google.come0d9ce82014-04-23 04:00:17 +00002799void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2800 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002801 SkPoint textOffset = SkPoint::Make(0, 0);
2802
halcanary96fcdcc2015-08-27 07:41:13 -07002803 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002804
reed@android.com8a1c16f2008-12-17 15:59:43 +00002805 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002806 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002807 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002808 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002810
reed@google.com4e2b3d32011-04-07 14:18:59 +00002811 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002812}
2813
reed@google.come0d9ce82014-04-23 04:00:17 +00002814void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2815 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002816
2817 SkPoint textOffset = SkPoint::Make(0, constY);
2818
halcanary96fcdcc2015-08-27 07:41:13 -07002819 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002820
reed@android.com8a1c16f2008-12-17 15:59:43 +00002821 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002822 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002823 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002824 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002825 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002826
reed@google.com4e2b3d32011-04-07 14:18:59 +00002827 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002828}
2829
reed@google.come0d9ce82014-04-23 04:00:17 +00002830void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2831 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002832 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002833
reed@android.com8a1c16f2008-12-17 15:59:43 +00002834 while (iter.next()) {
2835 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002836 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002838
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002839 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002840}
2841
reed45561a02016-07-07 12:47:17 -07002842void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2843 const SkRect* cullRect, const SkPaint& paint) {
2844 if (cullRect && this->quickReject(*cullRect)) {
2845 return;
2846 }
2847
2848 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2849
2850 while (iter.next()) {
2851 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2852 }
2853
2854 LOOPER_END
2855}
2856
fmalita00d5c2c2014-08-21 08:53:26 -07002857void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2858 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002859
fmalita85d5eb92015-03-04 11:20:12 -08002860 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002861 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002862 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002863 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002864 SkRect tmp;
2865 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2866 return;
2867 }
2868 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002869 }
2870
fmalita024f9962015-03-03 19:08:17 -08002871 // We cannot filter in the looper as we normally do, because the paint is
2872 // incomplete at this point (text-related attributes are embedded within blob run paints).
2873 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002874 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002875
fmalita85d5eb92015-03-04 11:20:12 -08002876 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002877
fmalitaaa1b9122014-08-28 14:32:24 -07002878 while (iter.next()) {
2879 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002880 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002881 }
2882
fmalitaaa1b9122014-08-28 14:32:24 -07002883 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002884
2885 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002886}
2887
reed@google.come0d9ce82014-04-23 04:00:17 +00002888// These will become non-virtual, so they always call the (virtual) onDraw... method
2889void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2890 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002891 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002892 if (byteLength) {
2893 this->onDrawText(text, byteLength, x, y, paint);
2894 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002895}
2896void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2897 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002898 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002899 if (byteLength) {
2900 this->onDrawPosText(text, byteLength, pos, paint);
2901 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002902}
2903void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2904 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002905 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002906 if (byteLength) {
2907 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2908 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002909}
2910void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2911 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002912 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002913 if (byteLength) {
2914 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2915 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002916}
reed45561a02016-07-07 12:47:17 -07002917void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2918 const SkRect* cullRect, const SkPaint& paint) {
2919 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2920 if (byteLength) {
2921 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2922 }
2923}
fmalita00d5c2c2014-08-21 08:53:26 -07002924void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2925 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002926 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002927 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002928 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002929}
reed@google.come0d9ce82014-04-23 04:00:17 +00002930
reed41af9662015-01-05 07:49:08 -08002931void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2932 const SkPoint verts[], const SkPoint texs[],
2933 const SkColor colors[], SkXfermode* xmode,
2934 const uint16_t indices[], int indexCount,
2935 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002936 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002937 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002938
reed@android.com8a1c16f2008-12-17 15:59:43 +00002939 while (iter.next()) {
2940 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002941 colors, xmode, indices, indexCount,
2942 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002943 }
reed@google.com4b226022011-01-11 18:32:13 +00002944
reed@google.com4e2b3d32011-04-07 14:18:59 +00002945 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002946}
2947
dandovb3c9d1c2014-08-12 08:34:29 -07002948void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2949 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002950 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002951 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002952 return;
2953 }
mtklein6cfa73a2014-08-13 13:33:49 -07002954
dandovecfff212014-08-04 10:02:00 -07002955 // Since a patch is always within the convex hull of the control points, we discard it when its
2956 // bounding rectangle is completely outside the current clip.
2957 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002958 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002959 if (this->quickReject(bounds)) {
2960 return;
2961 }
mtklein6cfa73a2014-08-13 13:33:49 -07002962
dandovb3c9d1c2014-08-12 08:34:29 -07002963 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2964}
2965
2966void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2967 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2968
halcanary96fcdcc2015-08-27 07:41:13 -07002969 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002970
dandovecfff212014-08-04 10:02:00 -07002971 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002972 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002973 }
mtklein6cfa73a2014-08-13 13:33:49 -07002974
dandovecfff212014-08-04 10:02:00 -07002975 LOOPER_END
2976}
2977
reeda8db7282015-07-07 10:22:31 -07002978void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002979 RETURN_ON_NULL(dr);
2980 if (x || y) {
2981 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2982 this->onDrawDrawable(dr, &matrix);
2983 } else {
2984 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002985 }
2986}
2987
reeda8db7282015-07-07 10:22:31 -07002988void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002989 RETURN_ON_NULL(dr);
2990 if (matrix && matrix->isIdentity()) {
2991 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002992 }
reede3b38ce2016-01-08 09:18:44 -08002993 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002994}
2995
2996void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2997 SkRect bounds = dr->getBounds();
2998 if (matrix) {
2999 matrix->mapRect(&bounds);
3000 }
3001 if (this->quickReject(bounds)) {
3002 return;
3003 }
3004 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08003005}
3006
reed71c3c762015-06-24 10:29:17 -07003007void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
3008 const SkColor colors[], int count, SkXfermode::Mode mode,
3009 const SkRect* cull, const SkPaint* paint) {
3010 if (cull && this->quickReject(*cull)) {
3011 return;
3012 }
3013
3014 SkPaint pnt;
3015 if (paint) {
3016 pnt = *paint;
3017 }
halcanary9d524f22016-03-29 09:03:52 -07003018
halcanary96fcdcc2015-08-27 07:41:13 -07003019 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07003020 while (iter.next()) {
3021 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
3022 }
3023 LOOPER_END
3024}
3025
reedf70b5312016-03-04 16:36:20 -08003026void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
3027 SkASSERT(key);
3028
3029 SkPaint paint;
3030 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
3031 while (iter.next()) {
3032 iter.fDevice->drawAnnotation(iter, rect, key, value);
3033 }
3034 LOOPER_END
3035}
3036
reed@android.com8a1c16f2008-12-17 15:59:43 +00003037//////////////////////////////////////////////////////////////////////////////
3038// These methods are NOT virtual, and therefore must call back into virtual
3039// methods, rather than actually drawing themselves.
3040//////////////////////////////////////////////////////////////////////////////
3041
3042void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00003043 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003044 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003045 SkPaint paint;
3046
3047 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00003048 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003049 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003050 }
3051 this->drawPaint(paint);
3052}
3053
reed@android.com845fdac2009-06-23 03:01:32 +00003054void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003055 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003056 SkPaint paint;
3057
3058 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00003059 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003060 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003061 }
3062 this->drawPaint(paint);
3063}
3064
3065void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003066 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003067 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00003068
reed@android.com8a1c16f2008-12-17 15:59:43 +00003069 pt.set(x, y);
3070 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3071}
3072
3073void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08003074 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003075 SkPoint pt;
3076 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00003077
reed@android.com8a1c16f2008-12-17 15:59:43 +00003078 pt.set(x, y);
3079 paint.setColor(color);
3080 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3081}
3082
3083void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
3084 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003085 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003086 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003087
reed@android.com8a1c16f2008-12-17 15:59:43 +00003088 pts[0].set(x0, y0);
3089 pts[1].set(x1, y1);
3090 this->drawPoints(kLines_PointMode, 2, pts, paint);
3091}
3092
3093void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3094 SkScalar right, SkScalar bottom,
3095 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003096 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003097 SkRect r;
3098
3099 r.set(left, top, right, bottom);
3100 this->drawRect(r, paint);
3101}
3102
3103void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3104 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003105 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003106 if (radius < 0) {
3107 radius = 0;
3108 }
3109
3110 SkRect r;
3111 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003112 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003113}
3114
3115void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3116 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003117 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003118 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003119 SkRRect rrect;
3120 rrect.setRectXY(r, rx, ry);
3121 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003122 } else {
3123 this->drawRect(r, paint);
3124 }
3125}
3126
reed@android.com8a1c16f2008-12-17 15:59:43 +00003127void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3128 SkScalar sweepAngle, bool useCenter,
3129 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003130 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
bsalomon21af9ca2016-08-25 12:29:23 -07003131 if (oval.isEmpty() || !sweepAngle) {
3132 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00003133 }
bsalomon21af9ca2016-08-25 12:29:23 -07003134 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003135}
3136
3137void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3138 const SkPath& path, SkScalar hOffset,
3139 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003140 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003141 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003142
reed@android.com8a1c16f2008-12-17 15:59:43 +00003143 matrix.setTranslate(hOffset, vOffset);
3144 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3145}
3146
reed@android.comf76bacf2009-05-13 14:00:33 +00003147///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003148
3149/**
3150 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3151 * against the playback cost of recursing into the subpicture to get at its actual ops.
3152 *
3153 * For now we pick a conservatively small value, though measurement (and other heuristics like
3154 * the type of ops contained) may justify changing this value.
3155 */
3156#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003157
reedd5fa1a42014-08-09 11:08:05 -07003158void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003159 RETURN_ON_NULL(picture);
3160
reed1c2c4412015-04-30 13:09:24 -07003161 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003162 if (matrix && matrix->isIdentity()) {
3163 matrix = nullptr;
3164 }
3165 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3166 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3167 picture->playback(this);
3168 } else {
3169 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003170 }
3171}
robertphillips9b14f262014-06-04 05:40:44 -07003172
reedd5fa1a42014-08-09 11:08:05 -07003173void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3174 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003175 if (!paint || paint->canComputeFastBounds()) {
3176 SkRect bounds = picture->cullRect();
3177 if (paint) {
3178 paint->computeFastBounds(bounds, &bounds);
3179 }
3180 if (matrix) {
3181 matrix->mapRect(&bounds);
3182 }
3183 if (this->quickReject(bounds)) {
3184 return;
3185 }
3186 }
3187
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003188 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003189 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003190}
3191
vjiaoblack95302da2016-07-21 10:25:54 -07003192#ifdef SK_EXPERIMENTAL_SHADOWING
3193void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3194 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003195 const SkPaint* paint,
3196 const SkShadowParams& params) {
vjiaoblack95302da2016-07-21 10:25:54 -07003197 RETURN_ON_NULL(picture);
3198
3199 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3200
vjiaoblacke6f5d562016-08-25 06:30:23 -07003201 this->onDrawShadowedPicture(picture, matrix, paint, params);
vjiaoblack95302da2016-07-21 10:25:54 -07003202}
3203
3204void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3205 const SkMatrix* matrix,
vjiaoblacke6f5d562016-08-25 06:30:23 -07003206 const SkPaint* paint,
3207 const SkShadowParams& params) {
vjiaoblack904527d2016-08-09 09:32:09 -07003208 if (!paint || paint->canComputeFastBounds()) {
3209 SkRect bounds = picture->cullRect();
3210 if (paint) {
3211 paint->computeFastBounds(bounds, &bounds);
3212 }
3213 if (matrix) {
3214 matrix->mapRect(&bounds);
3215 }
3216 if (this->quickReject(bounds)) {
3217 return;
3218 }
3219 }
3220
3221 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3222
vjiaoblacke6f5d562016-08-25 06:30:23 -07003223 sk_sp<SkImage> povDepthMap;
3224 sk_sp<SkImage> diffuseMap;
3225
3226 // TODO: pass the depth to the shader in vertices, or uniforms
3227 // so we don't have to render depth and color separately
vjiaoblack904527d2016-08-09 09:32:09 -07003228 for (int i = 0; i < fLights->numLights(); ++i) {
3229 // skip over ambient lights; they don't cast shadows
3230 // lights that have shadow maps do not need updating (because lights are immutable)
3231
vjiaoblacka8eabc42016-08-29 10:22:09 -07003232 if (fLights->light(i).getShadowMap() != nullptr) {
vjiaoblack904527d2016-08-09 09:32:09 -07003233 continue;
3234 }
3235
3236 // TODO: compute the correct size of the depth map from the light properties
3237 // TODO: maybe add a kDepth_8_SkColorType
3238 // TODO: find actual max depth of picture
3239 SkISize shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3240 fLights->light(i), 255,
3241 picture->cullRect().width(),
3242 picture->cullRect().height());
3243
3244 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3245 kBGRA_8888_SkColorType,
3246 kOpaque_SkAlphaType);
3247
3248 // Create a new surface (that matches the backend of canvas)
3249 // for each shadow map
3250 sk_sp<SkSurface> surf(this->makeSurface(info));
3251
3252 // Wrap another SPFCanvas around the surface
3253 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3254 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
vjiaoblacke6f5d562016-08-25 06:30:23 -07003255 depthMapCanvas->setShadowParams(params);
vjiaoblack904527d2016-08-09 09:32:09 -07003256
3257 // set the depth map canvas to have the light we're drawing.
3258 SkLights::Builder builder;
3259 builder.add(fLights->light(i));
3260 sk_sp<SkLights> curLight = builder.finish();
vjiaoblack904527d2016-08-09 09:32:09 -07003261 depthMapCanvas->setLights(std::move(curLight));
vjiaoblacke6f5d562016-08-25 06:30:23 -07003262
vjiaoblack904527d2016-08-09 09:32:09 -07003263 depthMapCanvas->drawPicture(picture);
vjiaoblacke6f5d562016-08-25 06:30:23 -07003264 sk_sp<SkImage> depthMap = surf->makeImageSnapshot();
vjiaoblack904527d2016-08-09 09:32:09 -07003265
vjiaoblacke6f5d562016-08-25 06:30:23 -07003266 if (params.fType == SkShadowParams::kNoBlur_ShadowType) {
3267 fLights->light(i).setShadowMap(std::move(depthMap));
3268 } else if (params.fType == SkShadowParams::kVariance_ShadowType) {
3269 // we blur the variance map
3270 SkPaint blurPaint;
3271 blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius,
3272 params.fShadowRadius, nullptr));
3273
3274 SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3275 kBGRA_8888_SkColorType,
3276 kOpaque_SkAlphaType);
3277
3278 sk_sp<SkSurface> blurSurf(this->makeSurface(blurInfo));
3279
3280 blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint);
3281
3282 fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot());
3283 }
vjiaoblack904527d2016-08-09 09:32:09 -07003284 }
3285
vjiaoblack904527d2016-08-09 09:32:09 -07003286 // povDepthMap
3287 {
3288 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003289 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3290 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003291 sk_sp<SkLights> povLight = builder.finish();
3292
3293 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3294 picture->cullRect().height(),
3295 kBGRA_8888_SkColorType,
3296 kOpaque_SkAlphaType);
3297
3298 // Create a new surface (that matches the backend of canvas)
3299 // to create the povDepthMap
3300 sk_sp<SkSurface> surf(this->makeSurface(info));
3301
3302 // Wrap another SPFCanvas around the surface
3303 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3304 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3305
3306 // set the depth map canvas to have the light as the user's POV
3307 depthMapCanvas->setLights(std::move(povLight));
3308
3309 depthMapCanvas->drawPicture(picture);
vjiaoblack904527d2016-08-09 09:32:09 -07003310 povDepthMap = surf->makeImageSnapshot();
3311 }
3312
3313 // diffuseMap
3314 {
3315 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3316 picture->cullRect().height(),
3317 kBGRA_8888_SkColorType,
3318 kOpaque_SkAlphaType);
3319
3320 sk_sp<SkSurface> surf(this->makeSurface(info));
3321 surf->getCanvas()->drawPicture(picture);
3322
3323 diffuseMap = surf->makeImageSnapshot();
3324 }
vjiaoblack904527d2016-08-09 09:32:09 -07003325 SkPaint shadowPaint;
3326
3327 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3328 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003329 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3330 SkShader::kClamp_TileMode);
vjiaoblack904527d2016-08-09 09:32:09 -07003331 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3332 std::move(diffuseShader),
3333 std::move(fLights),
3334 diffuseMap->width(),
vjiaoblacke6f5d562016-08-25 06:30:23 -07003335 diffuseMap->height(),
3336 params);
vjiaoblack904527d2016-08-09 09:32:09 -07003337
3338 shadowPaint.setShader(shadowShader);
3339
3340 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003341}
3342#endif
3343
reed@android.com8a1c16f2008-12-17 15:59:43 +00003344///////////////////////////////////////////////////////////////////////////////
3345///////////////////////////////////////////////////////////////////////////////
3346
reed3aafe112016-08-18 12:45:34 -07003347SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003348 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003349
3350 SkASSERT(canvas);
3351
reed3aafe112016-08-18 12:45:34 -07003352 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003353 fDone = !fImpl->next();
3354}
3355
3356SkCanvas::LayerIter::~LayerIter() {
3357 fImpl->~SkDrawIter();
3358}
3359
3360void SkCanvas::LayerIter::next() {
3361 fDone = !fImpl->next();
3362}
3363
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003364SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003365 return fImpl->getDevice();
3366}
3367
3368const SkMatrix& SkCanvas::LayerIter::matrix() const {
3369 return fImpl->getMatrix();
3370}
3371
3372const SkPaint& SkCanvas::LayerIter::paint() const {
3373 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003374 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003375 paint = &fDefaultPaint;
3376 }
3377 return *paint;
3378}
3379
reed1e7f5e72016-04-27 07:49:17 -07003380const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003381int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3382int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003383
3384///////////////////////////////////////////////////////////////////////////////
3385
fmalitac3b589a2014-06-05 12:40:07 -07003386SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003387
3388///////////////////////////////////////////////////////////////////////////////
3389
3390static bool supported_for_raster_canvas(const SkImageInfo& info) {
3391 switch (info.alphaType()) {
3392 case kPremul_SkAlphaType:
3393 case kOpaque_SkAlphaType:
3394 break;
3395 default:
3396 return false;
3397 }
3398
3399 switch (info.colorType()) {
3400 case kAlpha_8_SkColorType:
3401 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003402 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003403 break;
3404 default:
3405 return false;
3406 }
3407
3408 return true;
3409}
3410
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003411SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3412 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003413 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003414 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003415
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003416 SkBitmap bitmap;
3417 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003418 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003419 }
halcanary385fe4d2015-08-26 13:07:48 -07003420 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003421}
reedd5fa1a42014-08-09 11:08:05 -07003422
3423///////////////////////////////////////////////////////////////////////////////
3424
3425SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003426 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003427 : fCanvas(canvas)
3428 , fSaveCount(canvas->getSaveCount())
3429{
bsalomon49f085d2014-09-05 13:34:00 -07003430 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003431 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003432 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003433 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003434 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003435 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003436 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003437 canvas->save();
3438 }
mtklein6cfa73a2014-08-13 13:33:49 -07003439
bsalomon49f085d2014-09-05 13:34:00 -07003440 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003441 canvas->concat(*matrix);
3442 }
3443}
3444
3445SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3446 fCanvas->restoreToCount(fSaveCount);
3447}
reede8f30622016-03-23 18:59:25 -07003448
3449#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3450SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
3451 return this->makeSurface(info, props).release();
3452}
3453#endif