blob: bc5e030430ac0b84e660afedfa8f43b70376ab1c [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
42#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000044#if SK_SUPPORT_GPU
robertphillips7354a4b2015-12-16 05:08:27 -080045#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000046#include "GrRenderTarget.h"
bsalomon614d8f92016-07-13 15:42:40 -070047#include "SkGrPriv.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000048#endif
49
reede3b38ce2016-01-08 09:18:44 -080050#define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
51
reed2d1afab2016-06-29 14:33:11 -070052//#define SK_SUPPORT_PRECHECK_CLIPRECT
53
reedc83a2972015-07-16 07:40:45 -070054/*
55 * Return true if the drawing this rect would hit every pixels in the canvas.
56 *
57 * Returns false if
58 * - rect does not contain the canvas' bounds
59 * - paint is not fill
60 * - paint would blur or otherwise change the coverage of the rect
61 */
62bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
63 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070064 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
65 (int)kNone_ShaderOverrideOpacity,
66 "need_matching_enums0");
67 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
68 (int)kOpaque_ShaderOverrideOpacity,
69 "need_matching_enums1");
70 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
71 (int)kNotOpaque_ShaderOverrideOpacity,
72 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070073
74 const SkISize size = this->getBaseLayerSize();
75 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
76 if (!this->getClipStack()->quickContains(bounds)) {
77 return false;
78 }
79
80 if (rect) {
halcanaryc5769b22016-08-10 07:13:21 -070081 if (!this->getTotalMatrix().isScaleTranslate()) {
reedc83a2972015-07-16 07:40:45 -070082 return false; // conservative
83 }
halcanaryc5769b22016-08-10 07:13:21 -070084
85 SkRect devRect;
86 this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect);
87 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070088 return false;
89 }
90 }
91
92 if (paint) {
93 SkPaint::Style paintStyle = paint->getStyle();
94 if (!(paintStyle == SkPaint::kFill_Style ||
95 paintStyle == SkPaint::kStrokeAndFill_Style)) {
96 return false;
97 }
98 if (paint->getMaskFilter() || paint->getLooper()
99 || paint->getPathEffect() || paint->getImageFilter()) {
100 return false; // conservative
101 }
102 }
103 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
104}
105
106///////////////////////////////////////////////////////////////////////////////////////////////////
107
reedd990e2f2014-12-22 11:58:30 -0800108static bool gIgnoreSaveLayerBounds;
109void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
110 gIgnoreSaveLayerBounds = ignore;
111}
112bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
113 return gIgnoreSaveLayerBounds;
114}
115
reed0acf1b42014-12-22 16:12:38 -0800116static bool gTreatSpriteAsBitmap;
117void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
118 gTreatSpriteAsBitmap = spriteAsBitmap;
119}
120bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
121 return gTreatSpriteAsBitmap;
122}
123
reed@google.comda17f752012-08-16 18:27:05 +0000124// experimental for faster tiled drawing...
125//#define SK_ENABLE_CLIP_QUICKREJECT
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126//#define SK_TRACE_SAVERESTORE
127
128#ifdef SK_TRACE_SAVERESTORE
129 static int gLayerCounter;
130 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
131 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
132
133 static int gRecCounter;
134 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
135 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
136
137 static int gCanvasCounter;
138 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
139 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
140#else
141 #define inc_layer()
142 #define dec_layer()
143 #define inc_rec()
144 #define dec_rec()
145 #define inc_canvas()
146 #define dec_canvas()
147#endif
148
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000149typedef SkTLazy<SkPaint> SkLazyPaint;
150
reedc83a2972015-07-16 07:40:45 -0700151void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000152 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700153 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
154 ? SkSurface::kDiscard_ContentChangeMode
155 : SkSurface::kRetain_ContentChangeMode);
156 }
157}
158
159void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
160 ShaderOverrideOpacity overrideOpacity) {
161 if (fSurfaceBase) {
162 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
163 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
164 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
165 // and therefore we don't care which mode we're in.
166 //
167 if (fSurfaceBase->outstandingImageSnapshot()) {
168 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
169 mode = SkSurface::kDiscard_ContentChangeMode;
170 }
171 }
172 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000173 }
174}
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000178/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 The clip/matrix/proc are fields that reflect the top of the save/restore
180 stack. Whenever the canvas changes, it marks a dirty flag, and then before
181 these are used (assuming we're not on a layer) we rebuild these cache
182 values: they reflect the top of the save stack, but translated and clipped
183 by the device's XY offset and bitmap-bounds.
184*/
185struct DeviceCM {
186 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000187 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000188 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000189 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700190 const SkMatrix* fMatrix;
191 SkMatrix fMatrixStorage;
reed8c30a812016-04-20 16:36:51 -0700192 SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193
reed96e657d2015-03-10 17:30:07 -0700194 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed7503d602016-07-15 14:23:29 -0700195 bool conservativeRasterClip, const SkMatrix& stashed)
halcanary96fcdcc2015-08-27 07:41:13 -0700196 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700197 , fClip(conservativeRasterClip)
reed8c30a812016-04-20 16:36:51 -0700198 , fStashedMatrix(stashed)
reedd9544982014-09-09 18:46:22 -0700199 {
reed2c9e2002016-07-25 08:05:22 -0700200 SkSafeRef(device);
reed@google.com4b226022011-01-11 18:32:13 +0000201 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700202 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000203 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000205 ~DeviceCM() {
reed2c9e2002016-07-25 08:05:22 -0700206 SkSafeUnref(fDevice);
halcanary385fe4d2015-08-26 13:07:48 -0700207 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000208 }
reed@google.com4b226022011-01-11 18:32:13 +0000209
mtkleinfeaadee2015-04-08 11:25:48 -0700210 void reset(const SkIRect& bounds) {
211 SkASSERT(!fPaint);
212 SkASSERT(!fNext);
213 SkASSERT(fDevice);
214 fClip.setRect(bounds);
215 }
216
reed@google.com045e62d2011-10-24 12:19:46 +0000217 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
218 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000219 int x = fDevice->getOrigin().x();
220 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 int width = fDevice->width();
222 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000223
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 if ((x | y) == 0) {
225 fMatrix = &totalMatrix;
226 fClip = totalClip;
227 } else {
228 fMatrixStorage = totalMatrix;
229 fMatrixStorage.postTranslate(SkIntToScalar(-x),
230 SkIntToScalar(-y));
231 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000232
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 totalClip.translate(-x, -y, &fClip);
234 }
235
reed@google.com045e62d2011-10-24 12:19:46 +0000236 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
238 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000239
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000241 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 SkRegion::kDifference_Op);
243 }
reed@google.com4b226022011-01-11 18:32:13 +0000244
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000245 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
246
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247#ifdef SK_DEBUG
248 if (!fClip.isEmpty()) {
249 SkIRect deviceR;
250 deviceR.set(0, 0, width, height);
251 SkASSERT(deviceR.contains(fClip.getBounds()));
252 }
253#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000254 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255};
256
257/* This is the record we keep for each save/restore level in the stack.
258 Since a level optionally copies the matrix and/or stack, we have pointers
259 for these fields. If the value is copied for this level, the copy is
260 stored in the ...Storage field, and the pointer points to that. If the
261 value is not copied for this level, we ignore ...Storage, and just point
262 at the corresponding value in the previous level in the stack.
263*/
264class SkCanvas::MCRec {
265public:
reed1f836ee2014-07-07 07:49:34 -0700266 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700267 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 /* If there are any layers in the stack, this points to the top-most
269 one that is at or below this level in the stack (so we know what
270 bitmap/device to draw into from this level. This value is NOT
271 reference counted, since the real owner is either our fLayer field,
272 or a previous one in a lower level.)
273 */
reed2ff1fce2014-12-11 07:07:37 -0800274 DeviceCM* fTopLayer;
275 SkRasterClip fRasterClip;
276 SkMatrix fMatrix;
277 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278
vjiaoblacke5de1302016-07-13 14:05:28 -0700279 // This is the current cumulative depth (aggregate of all done translateZ calls)
280 SkScalar fCurDrawDepth;
281
reedd9544982014-09-09 18:46:22 -0700282 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700283 fFilter = nullptr;
284 fLayer = nullptr;
285 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800286 fMatrix.reset();
287 fDeferredSaveCount = 0;
vjiaoblacke5de1302016-07-13 14:05:28 -0700288 fCurDrawDepth = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700289
reedd9544982014-09-09 18:46:22 -0700290 // don't bother initializing fNext
291 inc_rec();
292 }
vjiaoblacke5de1302016-07-13 14:05:28 -0700293 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix),
294 fCurDrawDepth(prev.fCurDrawDepth) {
reedd9544982014-09-09 18:46:22 -0700295 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700296 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700297 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800298 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700299
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300 // don't bother initializing fNext
301 inc_rec();
302 }
303 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000304 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700305 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306 dec_rec();
307 }
mtkleinfeaadee2015-04-08 11:25:48 -0700308
309 void reset(const SkIRect& bounds) {
310 SkASSERT(fLayer);
311 SkASSERT(fDeferredSaveCount == 0);
312
313 fMatrix.reset();
314 fRasterClip.setRect(bounds);
315 fLayer->reset(bounds);
316 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000317};
318
319class SkDrawIter : public SkDraw {
320public:
reed3aafe112016-08-18 12:45:34 -0700321 SkDrawIter(SkCanvas* canvas) {
junov@google.com4370aed2012-01-18 16:21:08 +0000322 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000323 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324 canvas->updateDeviceCMCache();
325
reed687fa1c2015-04-07 08:00:56 -0700326 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 fCurrLayer = canvas->fMCRec->fTopLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328 }
reed@google.com4b226022011-01-11 18:32:13 +0000329
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330 bool next() {
331 // skip over recs with empty clips
reed3aafe112016-08-18 12:45:34 -0700332 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
333 fCurrLayer = fCurrLayer->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 }
335
reed@google.comf68c5e22012-02-24 16:38:58 +0000336 const DeviceCM* rec = fCurrLayer;
337 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338
339 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000340 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700342 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700343 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700344 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000346 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347
348 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700349 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000350
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 return true;
352 }
353 return false;
354 }
reed@google.com4b226022011-01-11 18:32:13 +0000355
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000356 SkBaseDevice* getDevice() const { return fDevice; }
reed1e7f5e72016-04-27 07:49:17 -0700357 const SkRasterClip& getClip() const { return *fRC; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000358 int getX() const { return fDevice->getOrigin().x(); }
359 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360 const SkMatrix& getMatrix() const { return *fMatrix; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000362
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363private:
364 SkCanvas* fCanvas;
365 const DeviceCM* fCurrLayer;
366 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367
368 typedef SkDraw INHERITED;
369};
370
371/////////////////////////////////////////////////////////////////////////////
372
reeddbc3cef2015-04-29 12:18:57 -0700373static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
374 return lazy->isValid() ? lazy->get() : lazy->set(orig);
375}
376
377/**
378 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700379 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700380 */
reedd053ce92016-03-22 10:17:23 -0700381static sk_sp<SkColorFilter> image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700382 SkImageFilter* imgf = paint.getImageFilter();
383 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700384 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700385 }
386
reedd053ce92016-03-22 10:17:23 -0700387 SkColorFilter* imgCFPtr;
388 if (!imgf->asAColorFilter(&imgCFPtr)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700389 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700390 }
reedd053ce92016-03-22 10:17:23 -0700391 sk_sp<SkColorFilter> imgCF(imgCFPtr);
reeddbc3cef2015-04-29 12:18:57 -0700392
393 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700394 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700395 // there is no existing paint colorfilter, so we can just return the imagefilter's
396 return imgCF;
397 }
398
399 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
400 // and we need to combine them into a single colorfilter.
reedd053ce92016-03-22 10:17:23 -0700401 return SkColorFilter::MakeComposeFilter(std::move(imgCF), sk_ref_sp(paintCF));
reeddbc3cef2015-04-29 12:18:57 -0700402}
403
senorblanco87e066e2015-10-28 11:23:36 -0700404/**
405 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
406 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
407 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
408 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
409 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
410 * conservative "effective" bounds based on the settings in the paint... with one exception. This
411 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
412 * deliberately ignored.
413 */
414static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
415 const SkRect& rawBounds,
416 SkRect* storage) {
417 SkPaint tmpUnfiltered(paint);
418 tmpUnfiltered.setImageFilter(nullptr);
419 if (tmpUnfiltered.canComputeFastBounds()) {
420 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
421 } else {
422 return rawBounds;
423 }
424}
425
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426class AutoDrawLooper {
427public:
senorblanco87e066e2015-10-28 11:23:36 -0700428 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
429 // paint. It's used to determine the size of the offscreen layer for filters.
430 // If null, the clip will be used instead.
reed3aafe112016-08-18 12:45:34 -0700431 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700432 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000433 fCanvas = canvas;
fmalita53d9f1c2016-01-25 06:23:54 -0800434#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435 fFilter = canvas->getDrawFilter();
fmalita77650002016-01-21 18:47:11 -0800436#else
437 fFilter = nullptr;
438#endif
reed4a8126e2014-09-22 07:29:03 -0700439 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000440 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700441 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000442 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443
reedd053ce92016-03-22 10:17:23 -0700444 auto simplifiedCF = image_to_color_filter(fOrigPaint);
reeddbc3cef2015-04-29 12:18:57 -0700445 if (simplifiedCF) {
446 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reedd053ce92016-03-22 10:17:23 -0700447 paint->setColorFilter(std::move(simplifiedCF));
halcanary96fcdcc2015-08-27 07:41:13 -0700448 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700449 fPaint = paint;
450 }
451
452 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700453 /**
454 * We implement ImageFilters for a given draw by creating a layer, then applying the
455 * imagefilter to the pixels of that layer (its backing surface/image), and then
456 * we call restore() to xfer that layer to the main canvas.
457 *
458 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
459 * 2. Generate the src pixels:
460 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
461 * return (fPaint). We then draw the primitive (using srcover) into a cleared
462 * buffer/surface.
463 * 3. Restore the layer created in #1
464 * The imagefilter is passed the buffer/surface from the layer (now filled with the
465 * src pixels of the primitive). It returns a new "filtered" buffer, which we
466 * draw onto the previous layer using the xfermode from the original paint.
467 */
reed@google.com8926b162012-03-23 15:36:36 +0000468 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700469 tmp.setImageFilter(fPaint->getImageFilter());
reedcfb6bdf2016-03-29 11:32:50 -0700470 tmp.setXfermode(sk_ref_sp(fPaint->getXfermode()));
senorblanco87e066e2015-10-28 11:23:36 -0700471 SkRect storage;
472 if (rawBounds) {
473 // Make rawBounds include all paint outsets except for those due to image filters.
474 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
475 }
reedbfd5f172016-01-07 11:28:08 -0800476 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
reed76033be2015-03-14 10:54:31 -0700477 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700478 fTempLayerForImageFilter = true;
479 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000480 }
481
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000482 if (SkDrawLooper* looper = paint.getLooper()) {
483 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
484 looper->contextSize());
485 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000486 fIsSimple = false;
487 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700488 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000489 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700490 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000491 }
492 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000493
reed@android.com8a1c16f2008-12-17 15:59:43 +0000494 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700495 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000496 fCanvas->internalRestore();
497 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000498 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000499 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000500
reed@google.com4e2b3d32011-04-07 14:18:59 +0000501 const SkPaint& paint() const {
502 SkASSERT(fPaint);
503 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000504 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000505
reed@google.com129ec222012-05-15 13:24:09 +0000506 bool next(SkDrawFilter::Type drawType) {
507 if (fDone) {
508 return false;
509 } else if (fIsSimple) {
510 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000511 return !fPaint->nothingToDraw();
512 } else {
513 return this->doNext(drawType);
514 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000515 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000516
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517private:
reeddbc3cef2015-04-29 12:18:57 -0700518 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
519 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000520 SkCanvas* fCanvas;
521 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000522 SkDrawFilter* fFilter;
523 const SkPaint* fPaint;
524 int fSaveCount;
reed5c476fb2015-04-20 08:04:21 -0700525 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000526 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000527 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000528 SkDrawLooper::Context* fLooperContext;
529 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000530
531 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000532};
533
reed@google.com129ec222012-05-15 13:24:09 +0000534bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700535 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000536 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700537 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000538
reeddbc3cef2015-04-29 12:18:57 -0700539 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
540 *fLazyPaintInit.get() : fOrigPaint);
reed@google.com129ec222012-05-15 13:24:09 +0000541
reed5c476fb2015-04-20 08:04:21 -0700542 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700543 paint->setImageFilter(nullptr);
544 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000545 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000546
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000547 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000548 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000549 return false;
550 }
551 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000552 if (!fFilter->filter(paint, drawType)) {
553 fDone = true;
554 return false;
555 }
halcanary96fcdcc2015-08-27 07:41:13 -0700556 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000557 // no looper means we only draw once
558 fDone = true;
559 }
560 }
561 fPaint = paint;
562
563 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000564 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000565 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000566 }
567
568 // call this after any possible paint modifiers
569 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700570 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000571 return false;
572 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000573 return true;
574}
575
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576////////// macros to place around the internal draw calls //////////////////
577
reed3aafe112016-08-18 12:45:34 -0700578#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
579 this->predrawNotify(); \
580 AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
581 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
reed262a71b2015-12-05 13:07:27 -0800582 SkDrawIter iter(this);
583
584
reed@google.com8926b162012-03-23 15:36:36 +0000585#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000586 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700587 AutoDrawLooper looper(this, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000588 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000589 SkDrawIter iter(this);
590
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000591#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000592 this->predrawNotify(); \
reed3aafe112016-08-18 12:45:34 -0700593 AutoDrawLooper looper(this, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000594 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000596
reedc83a2972015-07-16 07:40:45 -0700597#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
598 this->predrawNotify(bounds, &paint, auxOpaque); \
reed3aafe112016-08-18 12:45:34 -0700599 AutoDrawLooper looper(this, paint, false, bounds); \
reedc83a2972015-07-16 07:40:45 -0700600 while (looper.next(type)) { \
601 SkDrawIter iter(this);
602
reed@google.com4e2b3d32011-04-07 14:18:59 +0000603#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000604
605////////////////////////////////////////////////////////////////////////////
606
msarettfbfa2582016-08-12 08:29:08 -0700607static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
608 if (bounds.isEmpty()) {
609 return SkRect::MakeEmpty();
610 }
611
612 // Expand bounds out by 1 in case we are anti-aliasing. We store the
613 // bounds as floats to enable a faster quick reject implementation.
614 SkRect dst;
615 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
616 return dst;
617}
618
mtkleinfeaadee2015-04-08 11:25:48 -0700619void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
620 this->restoreToCount(1);
mtkleinfeaadee2015-04-08 11:25:48 -0700621 fClipStack->reset();
622 fMCRec->reset(bounds);
623
624 // We're peering through a lot of structs here. Only at this scope do we
625 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
626 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
msarettfbfa2582016-08-12 08:29:08 -0700627 fDeviceClipBounds = qr_clip_bounds(bounds);
msarett9637ea92016-08-18 14:03:30 -0700628 fIsScaleTranslate = true;
mtkleinfeaadee2015-04-08 11:25:48 -0700629}
630
reedd9544982014-09-09 18:46:22 -0700631SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800632 if (device && device->forceConservativeRasterClip()) {
633 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
634 }
635 // Since init() is only called once by our constructors, it is safe to perform this
636 // const-cast.
637 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
638
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000639 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000640 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700641 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800642 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700643 fMetaData = nullptr;
vjiaoblack95302da2016-07-21 10:25:54 -0700644#ifdef SK_EXPERIMENTAL_SHADOWING
645 fLights = nullptr;
646#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647
halcanary385fe4d2015-08-26 13:07:48 -0700648 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700649
reed@android.com8a1c16f2008-12-17 15:59:43 +0000650 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700651 new (fMCRec) MCRec(fConservativeRasterClip);
msarett9637ea92016-08-18 14:03:30 -0700652 fIsScaleTranslate = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653
reeda499f902015-05-01 09:34:31 -0700654 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
655 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed7503d602016-07-15 14:23:29 -0700656 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip,
reed8c30a812016-04-20 16:36:51 -0700657 fMCRec->fMatrix);
reedb679ca82015-04-07 04:40:48 -0700658
reed@android.com8a1c16f2008-12-17 15:59:43 +0000659 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000660
halcanary96fcdcc2015-08-27 07:41:13 -0700661 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000662
reedf92c8662014-08-18 08:02:43 -0700663 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700664 // The root device and the canvas should always have the same pixel geometry
665 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700666 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800667 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
msarettfbfa2582016-08-12 08:29:08 -0700668 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700669 }
msarettfbfa2582016-08-12 08:29:08 -0700670
reedf92c8662014-08-18 08:02:43 -0700671 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000672}
673
reed@google.comcde92112011-07-06 20:00:52 +0000674SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000675 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700676 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800677 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000678{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000679 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000680
halcanary96fcdcc2015-08-27 07:41:13 -0700681 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000682}
683
reedd9544982014-09-09 18:46:22 -0700684static SkBitmap make_nopixels(int width, int height) {
685 SkBitmap bitmap;
686 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
687 return bitmap;
688}
689
690class SkNoPixelsBitmapDevice : public SkBitmapDevice {
691public:
robertphillipsfcf78292015-06-19 11:49:52 -0700692 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
693 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800694 {
695 this->setOrigin(bounds.x(), bounds.y());
696 }
reedd9544982014-09-09 18:46:22 -0700697
698private:
piotaixrb5fae932014-09-24 13:03:30 -0700699
reedd9544982014-09-09 18:46:22 -0700700 typedef SkBitmapDevice INHERITED;
701};
702
reed96a857e2015-01-25 10:33:58 -0800703SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000704 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800705 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800706 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000707{
708 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700709
halcanary385fe4d2015-08-26 13:07:48 -0700710 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
711 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700712}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000713
reed78e27682014-11-19 08:04:34 -0800714SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700715 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700716 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800717 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700718{
719 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700720
halcanary385fe4d2015-08-26 13:07:48 -0700721 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700722}
723
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000724SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000725 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700726 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800727 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000728{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000729 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700730
reedd9544982014-09-09 18:46:22 -0700731 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732}
733
robertphillipsfcf78292015-06-19 11:49:52 -0700734SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
735 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700736 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800737 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700738{
739 inc_canvas();
740
741 this->init(device, flags);
742}
743
reed4a8126e2014-09-22 07:29:03 -0700744SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700745 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700746 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800747 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700748{
749 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700750
halcanary385fe4d2015-08-26 13:07:48 -0700751 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700752 this->init(device, kDefault_InitFlags);
753}
reed29c857d2014-09-21 10:25:07 -0700754
reed4a8126e2014-09-22 07:29:03 -0700755SkCanvas::SkCanvas(const SkBitmap& bitmap)
756 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
757 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800758 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700759{
760 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700761
halcanary385fe4d2015-08-26 13:07:48 -0700762 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700763 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000764}
765
766SkCanvas::~SkCanvas() {
767 // free up the contents of our deque
768 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000769
reed@android.com8a1c16f2008-12-17 15:59:43 +0000770 this->internalRestore(); // restore the last, since we're going away
771
halcanary385fe4d2015-08-26 13:07:48 -0700772 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000773
reed@android.com8a1c16f2008-12-17 15:59:43 +0000774 dec_canvas();
775}
776
fmalita53d9f1c2016-01-25 06:23:54 -0800777#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000778SkDrawFilter* SkCanvas::getDrawFilter() const {
779 return fMCRec->fFilter;
780}
781
782SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700783 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000784 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
785 return filter;
786}
fmalita77650002016-01-21 18:47:11 -0800787#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000788
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000789SkMetaData& SkCanvas::getMetaData() {
790 // metadata users are rare, so we lazily allocate it. If that changes we
791 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700792 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000793 fMetaData = new SkMetaData;
794 }
795 return *fMetaData;
796}
797
reed@android.com8a1c16f2008-12-17 15:59:43 +0000798///////////////////////////////////////////////////////////////////////////////
799
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000800void SkCanvas::flush() {
reedea5a6512016-07-07 16:44:27 -0700801 this->onFlush();
802}
803
804void SkCanvas::onFlush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000805 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000806 if (device) {
807 device->flush();
808 }
809}
810
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000811SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000812 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000813 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
814}
815
senorblancoafc7cce2016-02-02 18:44:15 -0800816SkIRect SkCanvas::getTopLayerBounds() const {
817 SkBaseDevice* d = this->getTopDevice();
818 if (!d) {
819 return SkIRect::MakeEmpty();
820 }
821 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
822}
823
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000824SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000826 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827 SkASSERT(rec && rec->fLayer);
828 return rec->fLayer->fDevice;
829}
830
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000831SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000832 if (updateMatrixClip) {
833 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
834 }
reed@google.com9266fed2011-03-30 00:18:03 +0000835 return fMCRec->fTopLayer->fDevice;
836}
837
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000838bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
reedc7ec7c92016-07-25 08:29:10 -0700839 if (kUnknown_SkColorType == bitmap->colorType()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000840 return false;
841 }
842
843 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700844 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700845 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000846 return false;
847 }
848 weAllocated = true;
849 }
850
reedcf01e312015-05-23 19:14:51 -0700851 SkAutoPixmapUnlock unlocker;
852 if (bitmap->requestLock(&unlocker)) {
853 const SkPixmap& pm = unlocker.pixmap();
854 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
855 return true;
856 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000857 }
858
859 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700860 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000861 }
862 return false;
863}
reed@google.com51df9e32010-12-23 19:29:18 +0000864
bsalomon@google.comc6980972011-11-02 19:57:21 +0000865bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000866 SkIRect r = srcRect;
867 const SkISize size = this->getBaseLayerSize();
868 if (!r.intersect(0, 0, size.width(), size.height())) {
869 bitmap->reset();
870 return false;
871 }
872
reed84825042014-09-02 12:50:45 -0700873 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000874 // bitmap will already be reset.
875 return false;
876 }
877 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
878 bitmap->reset();
879 return false;
880 }
881 return true;
882}
883
reed96472de2014-12-10 09:53:42 -0800884bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000885 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000886 if (!device) {
887 return false;
888 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000889 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800890
reed96472de2014-12-10 09:53:42 -0800891 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
892 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000893 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000894 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000895
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000896 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800897 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000898}
899
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000900bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
reedcf01e312015-05-23 19:14:51 -0700901 SkAutoPixmapUnlock unlocker;
902 if (bitmap.requestLock(&unlocker)) {
903 const SkPixmap& pm = unlocker.pixmap();
904 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000905 }
906 return false;
907}
908
909bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
910 int x, int y) {
911 switch (origInfo.colorType()) {
912 case kUnknown_SkColorType:
913 case kIndex_8_SkColorType:
914 return false;
915 default:
916 break;
917 }
halcanary96fcdcc2015-08-27 07:41:13 -0700918 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000919 return false;
920 }
921
922 const SkISize size = this->getBaseLayerSize();
923 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
924 if (!target.intersect(0, 0, size.width(), size.height())) {
925 return false;
926 }
927
928 SkBaseDevice* device = this->getDevice();
929 if (!device) {
930 return false;
931 }
932
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000933 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700934 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000935
936 // if x or y are negative, then we have to adjust pixels
937 if (x > 0) {
938 x = 0;
939 }
940 if (y > 0) {
941 y = 0;
942 }
943 // here x,y are either 0 or negative
944 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
945
reed4af35f32014-06-27 17:47:49 -0700946 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700947 const bool completeOverwrite = info.dimensions() == size;
948 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700949
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000950 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000951 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000952}
reed@google.com51df9e32010-12-23 19:29:18 +0000953
junov@google.com4370aed2012-01-18 16:21:08 +0000954SkCanvas* SkCanvas::canvasForDrawIter() {
955 return this;
956}
957
reed@android.com8a1c16f2008-12-17 15:59:43 +0000958//////////////////////////////////////////////////////////////////////////////
959
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960void SkCanvas::updateDeviceCMCache() {
961 if (fDeviceCMDirty) {
962 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700963 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000965
halcanary96fcdcc2015-08-27 07:41:13 -0700966 if (nullptr == layer->fNext) { // only one layer
967 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000969 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970 do {
reed687fa1c2015-04-07 08:00:56 -0700971 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700972 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973 }
974 fDeviceCMDirty = false;
975 }
976}
977
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978///////////////////////////////////////////////////////////////////////////////
979
reed2ff1fce2014-12-11 07:07:37 -0800980void SkCanvas::checkForDeferredSave() {
981 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800982 this->doSave();
983 }
984}
985
reedf0090cb2014-11-26 08:55:51 -0800986int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800987#ifdef SK_DEBUG
988 int count = 0;
989 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
990 for (;;) {
991 const MCRec* rec = (const MCRec*)iter.next();
992 if (!rec) {
993 break;
994 }
995 count += 1 + rec->fDeferredSaveCount;
996 }
997 SkASSERT(count == fSaveCount);
998#endif
999 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001000}
1001
1002int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001003 fSaveCount += 1;
1004 fMCRec->fDeferredSaveCount += 1;
1005 return this->getSaveCount() - 1; // return our prev value
1006}
1007
1008void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001009 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001010
1011 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1012 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001013 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001014}
1015
1016void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001017 if (fMCRec->fDeferredSaveCount > 0) {
1018 SkASSERT(fSaveCount > 1);
1019 fSaveCount -= 1;
1020 fMCRec->fDeferredSaveCount -= 1;
1021 } else {
1022 // check for underflow
1023 if (fMCStack.count() > 1) {
1024 this->willRestore();
1025 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001026 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001027 this->internalRestore();
1028 this->didRestore();
1029 }
reedf0090cb2014-11-26 08:55:51 -08001030 }
1031}
1032
1033void SkCanvas::restoreToCount(int count) {
1034 // sanity check
1035 if (count < 1) {
1036 count = 1;
1037 }
mtkleinf0f14112014-12-12 08:46:25 -08001038
reedf0090cb2014-11-26 08:55:51 -08001039 int n = this->getSaveCount() - count;
1040 for (int i = 0; i < n; ++i) {
1041 this->restore();
1042 }
1043}
1044
reed2ff1fce2014-12-11 07:07:37 -08001045void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001046 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001047 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001048 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001049
reed687fa1c2015-04-07 08:00:56 -07001050 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001051}
1052
reed4960eee2015-12-18 07:09:18 -08001053bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001054#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001055 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@google.comb93ba452014-03-10 19:47:58 +00001056#else
1057 return true;
1058#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059}
1060
reed4960eee2015-12-18 07:09:18 -08001061bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001062 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001063 SkIRect clipBounds;
1064 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001065 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001066 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001067
reed96e657d2015-03-10 17:30:07 -07001068 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1069
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001070 if (imageFilter) {
senorblancoe5e79842016-03-21 14:51:59 -07001071 clipBounds = imageFilter->filterBounds(clipBounds, ctm);
senorblancodb64af32015-12-09 10:11:43 -08001072 if (bounds && !imageFilter->canComputeFastBounds()) {
1073 bounds = nullptr;
1074 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001075 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001076 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001077 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001078 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001079
reed96e657d2015-03-10 17:30:07 -07001080 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001081 r.roundOut(&ir);
1082 // early exit if the layer's bounds are clipped out
1083 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001084 if (BoundsAffectsClip(saveLayerFlags)) {
reed1f836ee2014-07-07 07:49:34 -07001085 fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001086 fDeviceClipBounds.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001087 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001088 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089 }
1090 } else { // no user bounds, so just use the clip
1091 ir = clipBounds;
1092 }
reed180aec42015-03-11 10:39:04 -07001093 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001094
reed4960eee2015-12-18 07:09:18 -08001095 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001096 // Simplify the current clips since they will be applied properly during restore()
reed687fa1c2015-04-07 08:00:56 -07001097 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001098 fMCRec->fRasterClip.setRect(ir);
msarettfbfa2582016-08-12 08:29:08 -07001099 fDeviceClipBounds = qr_clip_bounds(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001100 }
1101
1102 if (intersection) {
1103 *intersection = ir;
1104 }
1105 return true;
1106}
1107
reed4960eee2015-12-18 07:09:18 -08001108
reed4960eee2015-12-18 07:09:18 -08001109int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1110 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001111}
1112
reed70ee31b2015-12-10 13:44:45 -08001113int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001114 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1115}
1116
1117int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1118 SaveLayerRec rec(origRec);
1119 if (gIgnoreSaveLayerBounds) {
1120 rec.fBounds = nullptr;
1121 }
1122 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1123 fSaveCount += 1;
1124 this->internalSaveLayer(rec, strategy);
1125 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001126}
1127
reeda2217ef2016-07-20 06:04:34 -07001128void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
1129 SkBaseDevice* dst, const SkMatrix& ctm,
1130 const SkClipStack* clipStack) {
1131 SkDraw draw;
1132 SkRasterClip rc;
1133 rc.setRect(SkIRect::MakeWH(dst->width(), dst->height()));
1134 if (!dst->accessPixels(&draw.fDst)) {
1135 draw.fDst.reset(dst->imageInfo(), nullptr, 0);
robertphillips7354a4b2015-12-16 05:08:27 -08001136 }
reeda2217ef2016-07-20 06:04:34 -07001137 draw.fMatrix = &SkMatrix::I();
1138 draw.fRC = &rc;
1139 draw.fClipStack = clipStack;
1140 draw.fDevice = dst;
robertphillips7354a4b2015-12-16 05:08:27 -08001141
1142 SkPaint p;
robertphillips372177e2016-03-30 07:32:28 -07001143 p.setImageFilter(filter->makeWithLocalMatrix(ctm));
reeda2217ef2016-07-20 06:04:34 -07001144
1145 int x = src->getOrigin().x() - dst->getOrigin().x();
1146 int y = src->getOrigin().y() - dst->getOrigin().y();
1147 auto special = src->snapSpecial();
1148 if (special) {
1149 dst->drawSpecial(draw, special.get(), x, y, p);
1150 }
robertphillips7354a4b2015-12-16 05:08:27 -08001151}
reed70ee31b2015-12-10 13:44:45 -08001152
reed129ed1c2016-02-22 06:42:31 -08001153static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1154 const SkPaint* paint) {
1155 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1156 // e.g. sRGB or F16, we can remove this check
brianosman52ede1d2016-06-20 08:25:02 -07001157 // SRGBTODO: Can we remove this check now?
reed129ed1c2016-02-22 06:42:31 -08001158 const bool hasImageFilter = paint && paint->getImageFilter();
1159
1160 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1161 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1162 // force to L32
1163 return SkImageInfo::MakeN32(w, h, alphaType);
1164 } else {
1165 // keep the same characteristics as the prev
brianosman52ede1d2016-06-20 08:25:02 -07001166 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace()));
reed129ed1c2016-02-22 06:42:31 -08001167 }
1168}
1169
reed4960eee2015-12-18 07:09:18 -08001170void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1171 const SkRect* bounds = rec.fBounds;
1172 const SkPaint* paint = rec.fPaint;
1173 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1174
reed@google.comb93ba452014-03-10 19:47:58 +00001175#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001176 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001177#endif
1178
reed8c30a812016-04-20 16:36:51 -07001179 SkLazyPaint lazyP;
1180 SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL;
1181 SkMatrix stashedMatrix = fMCRec->fMatrix;
reed8c30a812016-04-20 16:36:51 -07001182 SkMatrix remainder;
1183 SkSize scale;
1184 /*
1185 * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc.
1186 * but they do handle scaling. To accommodate this, we do the following:
1187 *
1188 * 1. Stash off the current CTM
1189 * 2. Decompose the CTM into SCALE and REMAINDER
1190 * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that
1191 * contains the REMAINDER
1192 * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM)
1193 * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output
1194 * of the original imagefilter, and draw that (via drawSprite)
1195 * 6. Unwack the CTM to its original state (i.e. stashedMatrix)
1196 *
1197 * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer
1198 * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter.
1199 */
reed96a04f32016-04-25 09:25:15 -07001200 if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() &&
reed8c30a812016-04-20 16:36:51 -07001201 stashedMatrix.decomposeScale(&scale, &remainder))
1202 {
1203 // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix
1204 this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height()));
1205 SkPaint* p = lazyP.set(*paint);
1206 p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder,
1207 SkFilterQuality::kLow_SkFilterQuality,
1208 sk_ref_sp(imageFilter)));
1209 imageFilter = p->getImageFilter();
1210 paint = p;
1211 }
reed8c30a812016-04-20 16:36:51 -07001212
junov@chromium.orga907ac32012-02-24 21:54:07 +00001213 // do this before we create the layer. We don't call the public save() since
1214 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001215 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001216
1217 fDeviceCMDirty = true;
1218
1219 SkIRect ir;
reed8c30a812016-04-20 16:36:51 -07001220 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) {
reed2ff1fce2014-12-11 07:07:37 -08001221 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222 }
1223
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001224 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1225 // the clipRectBounds() call above?
1226 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001227 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001228 }
1229
reed4960eee2015-12-18 07:09:18 -08001230 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001231 SkPixelGeometry geo = fProps.pixelGeometry();
1232 if (paint) {
reed76033be2015-03-14 10:54:31 -07001233 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001234 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001235 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001236 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001237 }
1238 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239
robertphillips5139e502016-07-19 05:10:40 -07001240 SkBaseDevice* priorDevice = this->getTopDevice();
reeda2217ef2016-07-20 06:04:34 -07001241 if (nullptr == priorDevice) {
reedb2db8982014-11-13 12:41:02 -08001242 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001243 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001244 }
reedb2db8982014-11-13 12:41:02 -08001245
robertphillips5139e502016-07-19 05:10:40 -07001246 SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque,
reed129ed1c2016-02-22 06:42:31 -08001247 paint);
1248
robertphillips5139e502016-07-19 05:10:40 -07001249 SkAutoTUnref<SkBaseDevice> newDevice;
reed61f501f2015-04-29 08:34:00 -07001250 {
reed70ee31b2015-12-10 13:44:45 -08001251 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001252 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001253 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001254 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
reedcd4051e2016-07-15 09:41:26 -07001255 preserveLCDText);
robertphillips5139e502016-07-19 05:10:40 -07001256 newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
1257 if (!newDevice) {
reed7503d602016-07-15 14:23:29 -07001258 SkErrorInternals::SetError(kInternalError_SkError,
1259 "Unable to create device for layer.");
1260 return;
reed61f501f2015-04-29 08:34:00 -07001261 }
bungeman@google.come25c6842011-08-17 14:53:54 +00001262 }
robertphillips5139e502016-07-19 05:10:40 -07001263 newDevice->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001264
robertphillips5139e502016-07-19 05:10:40 -07001265 DeviceCM* layer = new DeviceCM(newDevice, paint, this, fConservativeRasterClip, stashedMatrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266
1267 layer->fNext = fMCRec->fTopLayer;
1268 fMCRec->fLayer = layer;
1269 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reeda2217ef2016-07-20 06:04:34 -07001270
1271 if (rec.fBackdrop) {
1272 DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice,
1273 fMCRec->fMatrix, this->getClipStack());
1274 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275}
1276
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001277int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001278 if (0xFF == alpha) {
1279 return this->saveLayer(bounds, nullptr);
1280 } else {
1281 SkPaint tmpPaint;
1282 tmpPaint.setAlpha(alpha);
1283 return this->saveLayer(bounds, &tmpPaint);
1284 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001285}
1286
reed@android.com8a1c16f2008-12-17 15:59:43 +00001287void SkCanvas::internalRestore() {
1288 SkASSERT(fMCStack.count() != 0);
1289
1290 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291
reed687fa1c2015-04-07 08:00:56 -07001292 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001293
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001294 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 DeviceCM* layer = fMCRec->fLayer; // may be null
1296 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001297 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298
1299 // now do the normal restore()
1300 fMCRec->~MCRec(); // balanced in save()
1301 fMCStack.pop_back();
1302 fMCRec = (MCRec*)fMCStack.back();
1303
1304 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1305 since if we're being recorded, we don't want to record this (the
1306 recorder will have already recorded the restore).
1307 */
bsalomon49f085d2014-09-05 13:34:00 -07001308 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001310 const SkIPoint& origin = layer->fDevice->getOrigin();
reed7503d602016-07-15 14:23:29 -07001311 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint);
reed8c30a812016-04-20 16:36:51 -07001312 // restore what we smashed in internalSaveLayer
1313 fMCRec->fMatrix = layer->fStashedMatrix;
reed@google.com8926b162012-03-23 15:36:36 +00001314 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001316 delete layer;
reedb679ca82015-04-07 04:40:48 -07001317 } else {
1318 // we're at the root
reeda499f902015-05-01 09:34:31 -07001319 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001320 layer->~DeviceCM();
reed8c30a812016-04-20 16:36:51 -07001321 // no need to update fMCRec, 'cause we're killing the canvas
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001323 }
msarettfbfa2582016-08-12 08:29:08 -07001324
1325 if (fMCRec) {
msarett9637ea92016-08-18 14:03:30 -07001326 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
msarettfbfa2582016-08-12 08:29:08 -07001327 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1328 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001329}
1330
reede8f30622016-03-23 18:59:25 -07001331sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001332 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001333 props = &fProps;
1334 }
1335 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001336}
1337
reede8f30622016-03-23 18:59:25 -07001338sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001339 SkBaseDevice* dev = this->getDevice();
reede8f30622016-03-23 18:59:25 -07001340 return dev ? dev->makeSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001341}
1342
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001343SkImageInfo SkCanvas::imageInfo() const {
reedea5a6512016-07-07 16:44:27 -07001344 return this->onImageInfo();
1345}
1346
1347SkImageInfo SkCanvas::onImageInfo() const {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001348 SkBaseDevice* dev = this->getDevice();
1349 if (dev) {
1350 return dev->imageInfo();
1351 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001352 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001353 }
1354}
1355
brianosman898235c2016-04-06 07:38:23 -07001356bool SkCanvas::getProps(SkSurfaceProps* props) const {
reedea5a6512016-07-07 16:44:27 -07001357 return this->onGetProps(props);
1358}
1359
1360bool SkCanvas::onGetProps(SkSurfaceProps* props) const {
brianosman898235c2016-04-06 07:38:23 -07001361 SkBaseDevice* dev = this->getDevice();
1362 if (dev) {
1363 if (props) {
1364 *props = fProps;
1365 }
1366 return true;
1367 } else {
1368 return false;
1369 }
1370}
1371
reed6ceeebd2016-03-09 14:26:26 -08001372#ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001373const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001374 SkPixmap pmap;
reed6ceeebd2016-03-09 14:26:26 -08001375 if (this->peekPixels(&pmap)) {
1376 if (info) {
1377 *info = pmap.info();
1378 }
1379 if (rowBytes) {
1380 *rowBytes = pmap.rowBytes();
1381 }
1382 return pmap.addr();
reed884e97c2015-05-26 11:31:54 -07001383 }
reed6ceeebd2016-03-09 14:26:26 -08001384 return nullptr;
1385}
1386#endif
1387
1388bool SkCanvas::peekPixels(SkPixmap* pmap) {
1389 return this->onPeekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001390}
1391
reed884e97c2015-05-26 11:31:54 -07001392bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001393 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001394 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001395}
1396
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001397void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001398 SkPixmap pmap;
1399 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001400 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001401 }
1402 if (info) {
1403 *info = pmap.info();
1404 }
1405 if (rowBytes) {
1406 *rowBytes = pmap.rowBytes();
1407 }
1408 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001409 *origin = this->getTopDevice(false)->getOrigin();
1410 }
reed884e97c2015-05-26 11:31:54 -07001411 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001412}
1413
reed884e97c2015-05-26 11:31:54 -07001414bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001415 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001416 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001417}
1418
reed@android.com8a1c16f2008-12-17 15:59:43 +00001419/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420
reed7503d602016-07-15 14:23:29 -07001421void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001423 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424 paint = &tmp;
1425 }
reed@google.com4b226022011-01-11 18:32:13 +00001426
reed@google.com8926b162012-03-23 15:36:36 +00001427 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reeda2217ef2016-07-20 06:04:34 -07001428
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001430 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001431 paint = &looper.paint();
1432 SkImageFilter* filter = paint->getImageFilter();
1433 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
senorblancof35566e2016-04-18 10:32:02 -07001434 if (filter) {
reeda2217ef2016-07-20 06:04:34 -07001435 dstDev->drawSpecial(iter, srcDev->snapSpecial().get(), pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001436 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001437 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001438 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001439 }
reeda2217ef2016-07-20 06:04:34 -07001440
reed@google.com4e2b3d32011-04-07 14:18:59 +00001441 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442}
1443
reed32704672015-12-16 08:27:10 -08001444/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001445
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001446void SkCanvas::translate(SkScalar dx, SkScalar dy) {
mtkleincbdf0072016-08-19 09:05:27 -07001447 this->checkForDeferredSave();
1448 fDeviceCMDirty = true;
1449 fMCRec->fMatrix.preTranslate(dx,dy);
1450
1451 // Translate shouldn't affect the is-scale-translateness of the matrix.
1452 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
1453
1454 this->didTranslate(dx,dy);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001455}
1456
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001457void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001458 SkMatrix m;
1459 m.setScale(sx, sy);
1460 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001461}
1462
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001463void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001464 SkMatrix m;
1465 m.setRotate(degrees);
1466 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001467}
1468
bungeman7438bfc2016-07-12 15:01:19 -07001469void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
1470 SkMatrix m;
1471 m.setRotate(degrees, px, py);
1472 this->concat(m);
1473}
1474
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001475void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001476 SkMatrix m;
1477 m.setSkew(sx, sy);
1478 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001479}
1480
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001481void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001482 if (matrix.isIdentity()) {
1483 return;
1484 }
1485
reed2ff1fce2014-12-11 07:07:37 -08001486 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001487 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001488 fMCRec->fMatrix.preConcat(matrix);
msarett9637ea92016-08-18 14:03:30 -07001489 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001490 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001491}
1492
reed8c30a812016-04-20 16:36:51 -07001493void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001494 fDeviceCMDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001495 fMCRec->fMatrix = matrix;
msarett9da5a5a2016-08-19 08:38:36 -07001496 fIsScaleTranslate = matrix.isScaleTranslate();
reed8c30a812016-04-20 16:36:51 -07001497}
1498
1499void SkCanvas::setMatrix(const SkMatrix& matrix) {
1500 this->checkForDeferredSave();
1501 this->internalSetMatrix(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001502 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503}
1504
reed@android.com8a1c16f2008-12-17 15:59:43 +00001505void SkCanvas::resetMatrix() {
reed8c30a812016-04-20 16:36:51 -07001506 this->setMatrix(SkMatrix::I());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001507}
1508
vjiaoblack95302da2016-07-21 10:25:54 -07001509#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -07001510void SkCanvas::translateZ(SkScalar z) {
1511 this->checkForDeferredSave();
1512 this->fMCRec->fCurDrawDepth += z;
1513 this->didTranslateZ(z);
1514}
1515
1516SkScalar SkCanvas::getZ() const {
1517 return this->fMCRec->fCurDrawDepth;
1518}
1519
vjiaoblack95302da2016-07-21 10:25:54 -07001520void SkCanvas::setLights(sk_sp<SkLights> lights) {
1521 this->fLights = lights;
1522}
1523
1524sk_sp<SkLights> SkCanvas::getLights() const {
1525 return this->fLights;
1526}
1527#endif
1528
reed@android.com8a1c16f2008-12-17 15:59:43 +00001529//////////////////////////////////////////////////////////////////////////////
1530
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001531void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2d1afab2016-06-29 14:33:11 -07001532 if (!fAllowSoftClip) {
1533 doAA = false;
1534 }
1535
1536#ifdef SK_SUPPORT_PRECHECK_CLIPRECT
1537 // Check if we can quick-accept the clip call (and do nothing)
1538 //
reed74467162016-06-30 08:15:35 -07001539 if (SkRegion::kIntersect_Op == op && !doAA && fMCRec->fMatrix.isScaleTranslate()) {
halcanaryc5769b22016-08-10 07:13:21 -07001540 SkRect devR;
1541 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect);
reed2d1afab2016-06-29 14:33:11 -07001542 // NOTE: this check is CTM specific, since we might round differently with a different
1543 // CTM. Thus this is only 100% reliable if there is not global CTM scale to be
1544 // applied later (i.e. if this is going into a picture).
1545 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1546#if 0
1547 SkDebugf("ignored clipRect [%g %g %g %g]\n",
1548 rect.left(), rect.top(), rect.right(), rect.bottom());
1549#endif
1550 return;
1551 }
1552 }
1553#endif
1554
reed2ff1fce2014-12-11 07:07:37 -08001555 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001556 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1557 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001558}
1559
1560void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001561#ifdef SK_ENABLE_CLIP_QUICKREJECT
1562 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001563 if (fMCRec->fRasterClip.isEmpty()) {
reed2d1afab2016-06-29 14:33:11 -07001564 return;
reed@google.comda17f752012-08-16 18:27:05 +00001565 }
1566
reed@google.com3b3e8952012-08-16 20:53:31 +00001567 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001568 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001569 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001570
reed687fa1c2015-04-07 08:00:56 -07001571 fClipStack->clipEmpty();
reed2d1afab2016-06-29 14:33:11 -07001572 (void)fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001573 fDeviceClipBounds.setEmpty();
reed2d1afab2016-06-29 14:33:11 -07001574 return;
reed@google.comda17f752012-08-16 18:27:05 +00001575 }
1576 }
1577#endif
1578
reed74467162016-06-30 08:15:35 -07001579 const bool isScaleTrans = fMCRec->fMatrix.isScaleTranslate();
reedc64eff52015-11-21 12:39:45 -08001580 SkRect devR;
reed74467162016-06-30 08:15:35 -07001581 if (isScaleTrans) {
halcanaryc5769b22016-08-10 07:13:21 -07001582 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect);
reedc64eff52015-11-21 12:39:45 -08001583 }
bsalomonac8cabd2015-11-20 18:53:07 -08001584
reed2d1afab2016-06-29 14:33:11 -07001585#ifndef SK_SUPPORT_PRECHECK_CLIPRECT
reedc64eff52015-11-21 12:39:45 -08001586 if (SkRegion::kIntersect_Op == op &&
1587 kHard_ClipEdgeStyle == edgeStyle
reed74467162016-06-30 08:15:35 -07001588 && isScaleTrans)
reedc64eff52015-11-21 12:39:45 -08001589 {
1590 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1591#if 0
1592 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1593 rect.left(), rect.top(), rect.right(), rect.bottom());
1594#endif
1595 return;
1596 }
1597 }
reed2d1afab2016-06-29 14:33:11 -07001598#endif
reedc64eff52015-11-21 12:39:45 -08001599
1600 AutoValidateClip avc(this);
1601
1602 fDeviceCMDirty = true;
reedc64eff52015-11-21 12:39:45 -08001603
reed74467162016-06-30 08:15:35 -07001604 if (isScaleTrans) {
reedc64eff52015-11-21 12:39:45 -08001605 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1606 fClipStack->clipDevRect(devR, op, isAA);
senorblancoafc7cce2016-02-02 18:44:15 -08001607 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001608 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001609 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001610 // and clip against that, since it can handle any matrix. However, to
1611 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1612 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001613 SkPath path;
1614
1615 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001616 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001617 }
msarettfbfa2582016-08-12 08:29:08 -07001618
1619 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001620}
1621
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001622void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001623 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001624 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001625 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001626 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1627 } else {
1628 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001629 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001630}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001631
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001632void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001633 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001634 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001635 AutoValidateClip avc(this);
1636
1637 fDeviceCMDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001638 if (!fAllowSoftClip) {
1639 edgeStyle = kHard_ClipEdgeStyle;
1640 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001641
reed687fa1c2015-04-07 08:00:56 -07001642 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001643
senorblancoafc7cce2016-02-02 18:44:15 -08001644 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
robertphillips125f19a2015-11-23 09:00:05 -08001645 kSoft_ClipEdgeStyle == edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001646 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001647 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001648 }
1649
1650 SkPath path;
1651 path.addRRect(rrect);
1652 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001653 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001654}
1655
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001656void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001657 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001658 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001659
1660 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1661 SkRect r;
1662 if (path.isRect(&r)) {
1663 this->onClipRect(r, op, edgeStyle);
1664 return;
1665 }
1666 SkRRect rrect;
1667 if (path.isOval(&r)) {
1668 rrect.setOval(r);
1669 this->onClipRRect(rrect, op, edgeStyle);
1670 return;
1671 }
1672 if (path.isRRect(&rrect)) {
1673 this->onClipRRect(rrect, op, edgeStyle);
1674 return;
1675 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001676 }
robertphillips39f05382015-11-24 09:30:12 -08001677
1678 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001679}
1680
1681void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001682#ifdef SK_ENABLE_CLIP_QUICKREJECT
1683 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001684 if (fMCRec->fRasterClip.isEmpty()) {
reed2d1afab2016-06-29 14:33:11 -07001685 return;
reed@google.comda17f752012-08-16 18:27:05 +00001686 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001687
reed@google.com3b3e8952012-08-16 20:53:31 +00001688 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001689 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001690 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001691
reed687fa1c2015-04-07 08:00:56 -07001692 fClipStack->clipEmpty();
reed2d1afab2016-06-29 14:33:11 -07001693 (void)fMCRec->fRasterClip.setEmpty();
msarettfbfa2582016-08-12 08:29:08 -07001694 fDeviceClipBounds.setEmpty();
reed2d1afab2016-06-29 14:33:11 -07001695 return;
reed@google.comda17f752012-08-16 18:27:05 +00001696 }
1697 }
1698#endif
1699
reed@google.com5c3d1472011-02-22 19:12:23 +00001700 AutoValidateClip avc(this);
1701
reed@android.com8a1c16f2008-12-17 15:59:43 +00001702 fDeviceCMDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001703 if (!fAllowSoftClip) {
1704 edgeStyle = kHard_ClipEdgeStyle;
1705 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001706
1707 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001708 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001709
reed@google.comfe701122011-11-08 19:41:23 +00001710 // Check if the transfomation, or the original path itself
1711 // made us empty. Note this can also happen if we contained NaN
1712 // values. computing the bounds detects this, and will set our
1713 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1714 if (devPath.getBounds().isEmpty()) {
1715 // resetting the path will remove any NaN or other wanky values
1716 // that might upset our scan converter.
1717 devPath.reset();
1718 }
1719
reed@google.com5c3d1472011-02-22 19:12:23 +00001720 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001721 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001722
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001723 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001724 bool clipIsAA = getClipStack()->asPath(&devPath);
1725 if (clipIsAA) {
1726 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001727 }
fmalita1a481fe2015-02-04 07:39:34 -08001728
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001729 op = SkRegion::kReplace_Op;
1730 }
1731
senorblancoafc7cce2016-02-02 18:44:15 -08001732 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
msarettfbfa2582016-08-12 08:29:08 -07001733 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001734}
1735
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001736void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001737 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001738 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001739}
1740
1741void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001742 AutoValidateClip avc(this);
1743
reed@android.com8a1c16f2008-12-17 15:59:43 +00001744 fDeviceCMDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001745
reed@google.com5c3d1472011-02-22 19:12:23 +00001746 // todo: signal fClipStack that we have a region, and therefore (I guess)
1747 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001748 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001749
reed1f836ee2014-07-07 07:49:34 -07001750 fMCRec->fRasterClip.op(rgn, op);
msarettfbfa2582016-08-12 08:29:08 -07001751 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001752}
1753
reed@google.com819c9212011-02-23 18:56:55 +00001754#ifdef SK_DEBUG
1755void SkCanvas::validateClip() const {
1756 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001757 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001758 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001759 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001760 return;
1761 }
1762
reed@google.com819c9212011-02-23 18:56:55 +00001763 SkIRect ir;
1764 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001765 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001766
reed687fa1c2015-04-07 08:00:56 -07001767 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001768 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001769 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001770 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001771 case SkClipStack::Element::kRect_Type:
1772 element->getRect().round(&ir);
1773 tmpClip.op(ir, element->getOp());
1774 break;
1775 case SkClipStack::Element::kEmpty_Type:
1776 tmpClip.setEmpty();
1777 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001778 default: {
1779 SkPath path;
1780 element->asPath(&path);
senorblancoafc7cce2016-02-02 18:44:15 -08001781 tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001782 break;
1783 }
reed@google.com819c9212011-02-23 18:56:55 +00001784 }
1785 }
reed@google.com819c9212011-02-23 18:56:55 +00001786}
1787#endif
1788
reed@google.com90c07ea2012-04-13 13:50:27 +00001789void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001790 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001791 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001792
halcanary96fcdcc2015-08-27 07:41:13 -07001793 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001794 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001795 }
1796}
1797
reed@google.com5c3d1472011-02-22 19:12:23 +00001798///////////////////////////////////////////////////////////////////////////////
1799
reed@google.com754de5f2014-02-24 19:38:20 +00001800bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001801 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001802}
1803
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001804bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001805 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001806}
1807
msarettfbfa2582016-08-12 08:29:08 -07001808static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1809#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1810 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1811 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1812 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1813 return 0xF != _mm_movemask_ps(mask);
1814#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1815 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1816 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1817 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1818 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1819#else
1820 SkRect devRectAsRect;
1821 SkRect devClipAsRect;
1822 devRect.store(&devRectAsRect.fLeft);
1823 devClip.store(&devClipAsRect.fLeft);
1824 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1825#endif
1826}
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001827
msarettfbfa2582016-08-12 08:29:08 -07001828// It's important for this function to not be inlined. Otherwise the compiler will share code
1829// between the fast path and the slow path, resulting in two slow paths.
1830static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
1831 const SkMatrix& matrix) {
1832 SkRect deviceRect;
1833 matrix.mapRect(&deviceRect, src);
1834 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1835}
1836
1837bool SkCanvas::quickReject(const SkRect& src) const {
1838#ifdef SK_DEBUG
1839 // Verify that fDeviceClipBounds are set properly.
1840 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
reed1f836ee2014-07-07 07:49:34 -07001841 if (fMCRec->fRasterClip.isEmpty()) {
msarett0c685ee2016-08-14 13:51:16 -07001842 SkASSERT(fDeviceClipBounds.isEmpty());
reed@android.coma380ae42009-07-21 01:17:02 +00001843 } else {
msarettfbfa2582016-08-12 08:29:08 -07001844 SkASSERT(tmp == fDeviceClipBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001845 }
msarettfbfa2582016-08-12 08:29:08 -07001846
msarett9637ea92016-08-18 14:03:30 -07001847 // Verify that fIsScaleTranslate is set properly.
1848 SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate());
msarettfbfa2582016-08-12 08:29:08 -07001849#endif
1850
msarett9637ea92016-08-18 14:03:30 -07001851 if (!fIsScaleTranslate) {
msarettfbfa2582016-08-12 08:29:08 -07001852 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1853 }
1854
1855 // We inline the implementation of mapScaleTranslate() for the fast path.
1856 float sx = fMCRec->fMatrix.getScaleX();
1857 float sy = fMCRec->fMatrix.getScaleY();
1858 float tx = fMCRec->fMatrix.getTranslateX();
1859 float ty = fMCRec->fMatrix.getTranslateY();
1860 Sk4f scale(sx, sy, sx, sy);
1861 Sk4f trans(tx, ty, tx, ty);
1862
1863 // Apply matrix.
1864 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1865
1866 // Make sure left < right, top < bottom.
1867 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1868 Sk4f min = Sk4f::Min(ltrb, rblt);
1869 Sk4f max = Sk4f::Max(ltrb, rblt);
1870 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1871 // ARM this sequence generates the fastest (a single instruction).
1872 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1873
1874 // Check if the device rect is NaN or outside the clip.
1875 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001876}
1877
reed@google.com3b3e8952012-08-16 20:53:31 +00001878bool SkCanvas::quickReject(const SkPath& path) const {
1879 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001880}
1881
reed@google.com3b3e8952012-08-16 20:53:31 +00001882bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001883 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001884 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001885 return false;
1886 }
1887
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001888 SkMatrix inverse;
1889 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001890 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001891 if (bounds) {
1892 bounds->setEmpty();
1893 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001894 return false;
1895 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001896
bsalomon49f085d2014-09-05 13:34:00 -07001897 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001898 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001899 // adjust it outwards in case we are antialiasing
1900 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001901
reed@google.com8f4d2302013-12-17 16:44:46 +00001902 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1903 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001904 inverse.mapRect(bounds, r);
1905 }
1906 return true;
1907}
1908
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001909bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001910 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001911 if (clip.isEmpty()) {
1912 if (bounds) {
1913 bounds->setEmpty();
1914 }
1915 return false;
1916 }
1917
bsalomon49f085d2014-09-05 13:34:00 -07001918 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001919 *bounds = clip.getBounds();
1920 }
1921 return true;
1922}
1923
reed@android.com8a1c16f2008-12-17 15:59:43 +00001924const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001925 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001926}
1927
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001928const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001929 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001930}
1931
robertphillips175dd9b2016-04-28 14:32:04 -07001932GrDrawContext* SkCanvas::internal_private_accessTopLayerDrawContext() {
reed@google.com9c135db2014-03-12 18:28:35 +00001933 SkBaseDevice* dev = this->getTopDevice();
robertphillips175dd9b2016-04-28 14:32:04 -07001934 return dev ? dev->accessDrawContext() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001935}
1936
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001937GrContext* SkCanvas::getGrContext() {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001938 SkBaseDevice* device = this->getTopDevice();
reed86ae3d12016-04-26 06:57:31 -07001939 return device ? device->context() : nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001940}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001941
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001942void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1943 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001944 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001945 if (outer.isEmpty()) {
1946 return;
1947 }
1948 if (inner.isEmpty()) {
1949 this->drawRRect(outer, paint);
1950 return;
1951 }
1952
1953 // We don't have this method (yet), but technically this is what we should
1954 // be able to assert...
1955 // SkASSERT(outer.contains(inner));
1956 //
1957 // For now at least check for containment of bounds
1958 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1959
1960 this->onDrawDRRect(outer, inner, paint);
1961}
1962
reed41af9662015-01-05 07:49:08 -08001963// These need to stop being virtual -- clients need to override the onDraw... versions
1964
1965void SkCanvas::drawPaint(const SkPaint& paint) {
1966 this->onDrawPaint(paint);
1967}
1968
1969void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1970 this->onDrawRect(r, paint);
1971}
1972
1973void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1974 this->onDrawOval(r, paint);
1975}
1976
1977void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1978 this->onDrawRRect(rrect, paint);
1979}
1980
1981void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1982 this->onDrawPoints(mode, count, pts, paint);
1983}
1984
1985void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1986 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1987 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1988 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1989 indices, indexCount, paint);
1990}
1991
1992void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1993 this->onDrawPath(path, paint);
1994}
1995
reeda85d4d02015-05-06 12:56:48 -07001996void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08001997 RETURN_ON_NULL(image);
reeda85d4d02015-05-06 12:56:48 -07001998 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001999}
2000
reede47829b2015-08-06 10:02:53 -07002001void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
2002 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002003 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002004 if (dst.isEmpty() || src.isEmpty()) {
2005 return;
2006 }
2007 this->onDrawImageRect(image, &src, dst, paint, constraint);
2008}
reed41af9662015-01-05 07:49:08 -08002009
reed84984ef2015-07-17 07:09:43 -07002010void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
2011 const SkPaint* paint, SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002012 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002013 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002014}
2015
reede47829b2015-08-06 10:02:53 -07002016void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
2017 SrcRectConstraint constraint) {
reede3b38ce2016-01-08 09:18:44 -08002018 RETURN_ON_NULL(image);
reede47829b2015-08-06 10:02:53 -07002019 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
2020 constraint);
2021}
reede47829b2015-08-06 10:02:53 -07002022
reed4c21dc52015-06-25 12:32:03 -07002023void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2024 const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002025 RETURN_ON_NULL(image);
reed4c21dc52015-06-25 12:32:03 -07002026 if (dst.isEmpty()) {
2027 return;
2028 }
msarett552bca92016-08-03 06:53:26 -07002029 if (SkLatticeIter::Valid(image->width(), image->height(), center)) {
2030 this->onDrawImageNine(image, center, dst, paint);
2031 } else {
reede47829b2015-08-06 10:02:53 -07002032 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002033 }
reed4c21dc52015-06-25 12:32:03 -07002034}
2035
msarett16882062016-08-16 09:31:08 -07002036void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2037 const SkPaint* paint) {
2038 RETURN_ON_NULL(image);
2039 if (dst.isEmpty()) {
2040 return;
2041 }
2042 if (SkLatticeIter::Valid(image->width(), image->height(), lattice)) {
2043 this->onDrawImageLattice(image, lattice, dst, paint);
2044 } else {
2045 this->drawImageRect(image, dst, paint);
2046 }
2047}
2048
reed41af9662015-01-05 07:49:08 -08002049void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002050 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002051 return;
2052 }
reed41af9662015-01-05 07:49:08 -08002053 this->onDrawBitmap(bitmap, dx, dy, paint);
2054}
2055
reede47829b2015-08-06 10:02:53 -07002056void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002057 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002058 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07002059 return;
2060 }
reede47829b2015-08-06 10:02:53 -07002061 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08002062}
2063
reed84984ef2015-07-17 07:09:43 -07002064void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
2065 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07002066 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07002067}
2068
reede47829b2015-08-06 10:02:53 -07002069void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
2070 SrcRectConstraint constraint) {
2071 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2072 constraint);
2073}
reede47829b2015-08-06 10:02:53 -07002074
reed41af9662015-01-05 07:49:08 -08002075void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2076 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002077 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002078 return;
2079 }
msarett552bca92016-08-03 06:53:26 -07002080 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
2081 this->onDrawBitmapNine(bitmap, center, dst, paint);
2082 } else {
reeda5517e22015-07-14 10:54:12 -07002083 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002084 }
reed41af9662015-01-05 07:49:08 -08002085}
2086
msarettc573a402016-08-02 08:05:56 -07002087void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
2088 const SkPaint* paint) {
msarett16882062016-08-16 09:31:08 -07002089 if (bitmap.drawsNothing() || dst.isEmpty()) {
msarettc573a402016-08-02 08:05:56 -07002090 return;
2091 }
msarett16882062016-08-16 09:31:08 -07002092 if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), lattice)) {
2093 this->onDrawBitmapLattice(bitmap, lattice, dst, paint);
msarett552bca92016-08-03 06:53:26 -07002094 } else {
msarett16882062016-08-16 09:31:08 -07002095 this->drawBitmapRect(bitmap, dst, paint);
msarettc573a402016-08-02 08:05:56 -07002096 }
msarettc573a402016-08-02 08:05:56 -07002097}
2098
reed71c3c762015-06-24 10:29:17 -07002099void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2100 const SkColor colors[], int count, SkXfermode::Mode mode,
2101 const SkRect* cull, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08002102 RETURN_ON_NULL(atlas);
reed71c3c762015-06-24 10:29:17 -07002103 if (count <= 0) {
2104 return;
2105 }
2106 SkASSERT(atlas);
2107 SkASSERT(xform);
2108 SkASSERT(tex);
2109 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2110}
2111
reedf70b5312016-03-04 16:36:20 -08002112void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2113 if (key) {
2114 this->onDrawAnnotation(rect, key, value);
2115 }
2116}
2117
reede47829b2015-08-06 10:02:53 -07002118void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2119 const SkPaint* paint, SrcRectConstraint constraint) {
2120 if (src) {
2121 this->drawImageRect(image, *src, dst, paint, constraint);
2122 } else {
2123 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2124 dst, paint, constraint);
2125 }
2126}
2127void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2128 const SkPaint* paint, SrcRectConstraint constraint) {
2129 if (src) {
2130 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2131 } else {
2132 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2133 dst, paint, constraint);
2134 }
2135}
2136
tomhudsoncb3bd182016-05-18 07:24:16 -07002137void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) {
2138 SkIRect layer_bounds = this->getTopLayerBounds();
2139 if (matrix) {
2140 *matrix = this->getTotalMatrix();
2141 matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top());
2142 }
2143 if (clip_bounds) {
2144 this->getClipDeviceBounds(clip_bounds);
2145 clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top());
2146 }
2147}
2148
reed@android.com8a1c16f2008-12-17 15:59:43 +00002149//////////////////////////////////////////////////////////////////////////////
2150// These are the virtual drawing methods
2151//////////////////////////////////////////////////////////////////////////////
2152
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002153void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002154 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002155 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2156 }
2157}
2158
reed41af9662015-01-05 07:49:08 -08002159void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002160 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002161 this->internalDrawPaint(paint);
2162}
2163
2164void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002165 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002166
2167 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002168 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002169 }
2170
reed@google.com4e2b3d32011-04-07 14:18:59 +00002171 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002172}
2173
reed41af9662015-01-05 07:49:08 -08002174void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2175 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002176 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002177 if ((long)count <= 0) {
2178 return;
2179 }
2180
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002181 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002182 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002183 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002184 // special-case 2 points (common for drawing a single line)
2185 if (2 == count) {
2186 r.set(pts[0], pts[1]);
2187 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002188 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002189 }
senorblanco87e066e2015-10-28 11:23:36 -07002190 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2191 return;
2192 }
2193 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002194 }
reed@google.coma584aed2012-05-16 14:06:02 +00002195
halcanary96fcdcc2015-08-27 07:41:13 -07002196 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002197
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002198 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002199
reed@android.com8a1c16f2008-12-17 15:59:43 +00002200 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002201 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002202 }
reed@google.com4b226022011-01-11 18:32:13 +00002203
reed@google.com4e2b3d32011-04-07 14:18:59 +00002204 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002205}
2206
reed4a167172016-08-18 17:15:25 -07002207static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) {
2208 return ((intptr_t)paint.getImageFilter() |
2209#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
2210 (intptr_t)canvas->getDrawFilter() |
2211#endif
2212 (intptr_t)paint.getLooper() ) != 0;
2213}
2214
reed41af9662015-01-05 07:49:08 -08002215void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002216 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002217 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002218 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002219 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002220 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2221 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2222 SkRect tmp(r);
2223 tmp.sort();
2224
senorblanco87e066e2015-10-28 11:23:36 -07002225 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2226 return;
2227 }
2228 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002229 }
reed@google.com4b226022011-01-11 18:32:13 +00002230
reed4a167172016-08-18 17:15:25 -07002231 if (needs_autodrawlooper(this, paint)) {
2232 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002233
reed4a167172016-08-18 17:15:25 -07002234 while (iter.next()) {
2235 iter.fDevice->drawRect(iter, r, looper.paint());
2236 }
2237
2238 LOOPER_END
2239 } else {
2240 this->predrawNotify(bounds, &paint, false);
2241 SkDrawIter iter(this);
2242 while (iter.next()) {
2243 iter.fDevice->drawRect(iter, r, paint);
2244 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002245 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002246}
2247
reed41af9662015-01-05 07:49:08 -08002248void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002249 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002250 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002251 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002252 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002253 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2254 return;
2255 }
2256 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002257 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002258
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002259 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002260
2261 while (iter.next()) {
2262 iter.fDevice->drawOval(iter, oval, looper.paint());
2263 }
2264
2265 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002266}
2267
bsalomonac3aa242016-08-19 11:25:19 -07002268void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
2269 SkScalar sweepAngle, bool useCenter,
2270 const SkPaint& paint) {
2271 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2272 const SkRect* bounds = nullptr;
2273 if (paint.canComputeFastBounds()) {
2274 SkRect storage;
2275 // Note we're using the entire oval as the bounds.
2276 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2277 return;
2278 }
2279 bounds = &oval;
2280 }
2281
2282 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2283
2284 while (iter.next()) {
2285 iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint());
2286 }
2287
2288 LOOPER_END
2289}
2290
reed41af9662015-01-05 07:49:08 -08002291void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002292 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002293 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002294 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002295 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002296 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2297 return;
2298 }
2299 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002300 }
2301
2302 if (rrect.isRect()) {
2303 // call the non-virtual version
2304 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002305 return;
2306 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002307 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002308 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2309 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002310 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002311
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002312 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002313
2314 while (iter.next()) {
2315 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2316 }
2317
2318 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002319}
2320
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002321void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2322 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002323 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002324 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002325 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002326 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2327 return;
2328 }
2329 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002330 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002331
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002332 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002333
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002334 while (iter.next()) {
2335 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2336 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002337
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002338 LOOPER_END
2339}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002340
reed41af9662015-01-05 07:49:08 -08002341void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002342 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002343 if (!path.isFinite()) {
2344 return;
2345 }
2346
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002347 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002348 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002349 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002350 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002351 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2352 return;
2353 }
2354 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002355 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002356
2357 const SkRect& r = path.getBounds();
2358 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002359 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002360 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002361 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002362 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002363 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002364
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002365 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002366
2367 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002368 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002369 }
2370
reed@google.com4e2b3d32011-04-07 14:18:59 +00002371 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002372}
2373
reed262a71b2015-12-05 13:07:27 -08002374bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002375 if (!paint.getImageFilter()) {
2376 return false;
2377 }
2378
2379 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002380 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002381 return false;
2382 }
2383
2384 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2385 // Once we can filter and the filter will return a result larger than itself, we should be
2386 // able to remove this constraint.
2387 // skbug.com/4526
2388 //
2389 SkPoint pt;
2390 ctm.mapXY(x, y, &pt);
2391 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2392 return ir.contains(fMCRec->fRasterClip.getBounds());
2393}
2394
reeda85d4d02015-05-06 12:56:48 -07002395void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002396 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002397 SkRect bounds = SkRect::MakeXYWH(x, y,
2398 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002399 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002400 SkRect tmp = bounds;
2401 if (paint) {
2402 paint->computeFastBounds(tmp, &tmp);
2403 }
2404 if (this->quickReject(tmp)) {
2405 return;
2406 }
reeda85d4d02015-05-06 12:56:48 -07002407 }
halcanary9d524f22016-03-29 09:03:52 -07002408
reeda85d4d02015-05-06 12:56:48 -07002409 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002410 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002411 paint = lazy.init();
2412 }
reed262a71b2015-12-05 13:07:27 -08002413
reeda2217ef2016-07-20 06:04:34 -07002414 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002415 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2416 *paint);
2417 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002418 special = this->getDevice()->makeSpecial(image);
2419 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002420 drawAsSprite = false;
reed129ed1c2016-02-22 06:42:31 -08002421 }
2422 }
2423
reed262a71b2015-12-05 13:07:27 -08002424 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2425
reeda85d4d02015-05-06 12:56:48 -07002426 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002427 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002428 if (special) {
2429 SkPoint pt;
2430 iter.fMatrix->mapXY(x, y, &pt);
2431 iter.fDevice->drawSpecial(iter, special.get(),
2432 SkScalarRoundToInt(pt.fX),
2433 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002434 } else {
2435 iter.fDevice->drawImage(iter, image, x, y, pnt);
2436 }
reeda85d4d02015-05-06 12:56:48 -07002437 }
halcanary9d524f22016-03-29 09:03:52 -07002438
reeda85d4d02015-05-06 12:56:48 -07002439 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002440}
2441
reed41af9662015-01-05 07:49:08 -08002442void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002443 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002444 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002445 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002446 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002447 if (paint) {
2448 paint->computeFastBounds(dst, &storage);
2449 }
2450 if (this->quickReject(storage)) {
2451 return;
2452 }
reeda85d4d02015-05-06 12:56:48 -07002453 }
2454 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002455 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002456 paint = lazy.init();
2457 }
halcanary9d524f22016-03-29 09:03:52 -07002458
senorblancoc41e7e12015-12-07 12:51:30 -08002459 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002460 image->isOpaque())
halcanary9d524f22016-03-29 09:03:52 -07002461
reeda85d4d02015-05-06 12:56:48 -07002462 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002463 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002464 }
halcanary9d524f22016-03-29 09:03:52 -07002465
reeda85d4d02015-05-06 12:56:48 -07002466 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002467}
2468
reed41af9662015-01-05 07:49:08 -08002469void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002470 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002471 SkDEBUGCODE(bitmap.validate();)
2472
reed33366972015-10-08 09:22:02 -07002473 if (bitmap.drawsNothing()) {
2474 return;
2475 }
2476
2477 SkLazyPaint lazy;
2478 if (nullptr == paint) {
2479 paint = lazy.init();
2480 }
2481
2482 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2483
2484 SkRect storage;
2485 const SkRect* bounds = nullptr;
2486 if (paint->canComputeFastBounds()) {
2487 bitmap.getBounds(&storage);
2488 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002489 SkRect tmp = storage;
2490 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2491 return;
2492 }
2493 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002494 }
reed@google.com4b226022011-01-11 18:32:13 +00002495
reeda2217ef2016-07-20 06:04:34 -07002496 sk_sp<SkSpecialImage> special;
reed129ed1c2016-02-22 06:42:31 -08002497 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2498 *paint);
2499 if (drawAsSprite && paint->getImageFilter()) {
reeda2217ef2016-07-20 06:04:34 -07002500 special = this->getDevice()->makeSpecial(bitmap);
2501 if (!special) {
reed129ed1c2016-02-22 06:42:31 -08002502 drawAsSprite = false;
2503 }
2504 }
2505
reed262a71b2015-12-05 13:07:27 -08002506 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002507
2508 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002509 const SkPaint& pnt = looper.paint();
reeda2217ef2016-07-20 06:04:34 -07002510 if (special) {
reed262a71b2015-12-05 13:07:27 -08002511 SkPoint pt;
2512 iter.fMatrix->mapXY(x, y, &pt);
reeda2217ef2016-07-20 06:04:34 -07002513 iter.fDevice->drawSpecial(iter, special.get(),
2514 SkScalarRoundToInt(pt.fX),
2515 SkScalarRoundToInt(pt.fY), pnt);
reed262a71b2015-12-05 13:07:27 -08002516 } else {
2517 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2518 }
reed33366972015-10-08 09:22:02 -07002519 }
msarettfbfa2582016-08-12 08:29:08 -07002520
reed33366972015-10-08 09:22:02 -07002521 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002522}
2523
reed@google.com9987ec32011-09-07 11:57:52 +00002524// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002525void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002526 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002527 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002528 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002529 return;
2530 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002531
halcanary96fcdcc2015-08-27 07:41:13 -07002532 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002533 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002534 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2535 return;
2536 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002537 }
reed@google.com3d608122011-11-21 15:16:16 +00002538
reed@google.com33535f32012-09-25 15:37:50 +00002539 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002540 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002541 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002542 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002543
senorblancoc41e7e12015-12-07 12:51:30 -08002544 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002545 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002546
reed@google.com33535f32012-09-25 15:37:50 +00002547 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002548 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002549 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002550
reed@google.com33535f32012-09-25 15:37:50 +00002551 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002552}
2553
reed41af9662015-01-05 07:49:08 -08002554void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002555 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002556 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002557 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002558 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002559}
2560
reed4c21dc52015-06-25 12:32:03 -07002561void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2562 const SkPaint* paint) {
2563 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
halcanary9d524f22016-03-29 09:03:52 -07002564
halcanary96fcdcc2015-08-27 07:41:13 -07002565 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002566 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002567 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2568 return;
2569 }
reed@google.com3d608122011-11-21 15:16:16 +00002570 }
halcanary9d524f22016-03-29 09:03:52 -07002571
reed4c21dc52015-06-25 12:32:03 -07002572 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002573 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002574 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002575 }
halcanary9d524f22016-03-29 09:03:52 -07002576
senorblancoc41e7e12015-12-07 12:51:30 -08002577 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002578
reed4c21dc52015-06-25 12:32:03 -07002579 while (iter.next()) {
2580 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002581 }
halcanary9d524f22016-03-29 09:03:52 -07002582
reed4c21dc52015-06-25 12:32:03 -07002583 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002584}
2585
reed41af9662015-01-05 07:49:08 -08002586void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2587 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002588 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002589 SkDEBUGCODE(bitmap.validate();)
2590
halcanary96fcdcc2015-08-27 07:41:13 -07002591 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002592 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002593 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2594 return;
2595 }
reed4c21dc52015-06-25 12:32:03 -07002596 }
halcanary9d524f22016-03-29 09:03:52 -07002597
reed4c21dc52015-06-25 12:32:03 -07002598 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002599 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002600 paint = lazy.init();
2601 }
halcanary9d524f22016-03-29 09:03:52 -07002602
senorblancoc41e7e12015-12-07 12:51:30 -08002603 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
halcanary9d524f22016-03-29 09:03:52 -07002604
reed4c21dc52015-06-25 12:32:03 -07002605 while (iter.next()) {
2606 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2607 }
halcanary9d524f22016-03-29 09:03:52 -07002608
reed4c21dc52015-06-25 12:32:03 -07002609 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002610}
2611
msarett16882062016-08-16 09:31:08 -07002612void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
2613 const SkPaint* paint) {
2614 if (nullptr == paint || paint->canComputeFastBounds()) {
2615 SkRect storage;
2616 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2617 return;
2618 }
2619 }
2620
2621 SkLazyPaint lazy;
2622 if (nullptr == paint) {
2623 paint = lazy.init();
2624 }
2625
2626 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2627
2628 while (iter.next()) {
2629 iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
2630 }
2631
2632 LOOPER_END
2633}
2634
2635void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
2636 const SkRect& dst, const SkPaint* paint) {
2637 if (nullptr == paint || paint->canComputeFastBounds()) {
2638 SkRect storage;
2639 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2640 return;
2641 }
2642 }
2643
2644 SkLazyPaint lazy;
2645 if (nullptr == paint) {
2646 paint = lazy.init();
2647 }
2648
2649 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2650
2651 while (iter.next()) {
2652 iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint());
2653 }
2654
2655 LOOPER_END
2656}
2657
reed@google.comf67e4cf2011-03-15 20:56:58 +00002658class SkDeviceFilteredPaint {
2659public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002660 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002661 uint32_t filteredFlags = device->filterTextFlags(paint);
2662 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002663 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002664 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002665 fPaint = newPaint;
2666 } else {
2667 fPaint = &paint;
2668 }
2669 }
2670
reed@google.comf67e4cf2011-03-15 20:56:58 +00002671 const SkPaint& paint() const { return *fPaint; }
2672
2673private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002674 const SkPaint* fPaint;
2675 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002676};
2677
bungeman@google.com52c748b2011-08-22 21:30:43 +00002678void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2679 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002680 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002681 draw.fDevice->drawRect(draw, r, paint);
2682 } else {
2683 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002684 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002685 draw.fDevice->drawRect(draw, r, p);
2686 }
2687}
2688
2689void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2690 const char text[], size_t byteLength,
2691 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002692 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002693
2694 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002695 if (text == nullptr || byteLength == 0 ||
reed1e7f5e72016-04-27 07:49:17 -07002696 draw.fRC->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002697 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002698 return;
2699 }
2700
2701 SkScalar width = 0;
2702 SkPoint start;
2703
2704 start.set(0, 0); // to avoid warning
2705 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2706 SkPaint::kStrikeThruText_Flag)) {
2707 width = paint.measureText(text, byteLength);
2708
2709 SkScalar offsetX = 0;
2710 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2711 offsetX = SkScalarHalf(width);
2712 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2713 offsetX = width;
2714 }
2715 start.set(x - offsetX, y);
2716 }
2717
2718 if (0 == width) {
2719 return;
2720 }
2721
2722 uint32_t flags = paint.getFlags();
2723
2724 if (flags & (SkPaint::kUnderlineText_Flag |
2725 SkPaint::kStrikeThruText_Flag)) {
2726 SkScalar textSize = paint.getTextSize();
2727 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2728 SkRect r;
2729
2730 r.fLeft = start.fX;
2731 r.fRight = start.fX + width;
2732
2733 if (flags & SkPaint::kUnderlineText_Flag) {
2734 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2735 start.fY);
2736 r.fTop = offset;
2737 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002738 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002739 }
2740 if (flags & SkPaint::kStrikeThruText_Flag) {
2741 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2742 start.fY);
2743 r.fTop = offset;
2744 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002745 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002746 }
2747 }
2748}
2749
reed@google.come0d9ce82014-04-23 04:00:17 +00002750void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2751 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002752 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753
2754 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002755 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002756 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002757 DrawTextDecorations(iter, dfp.paint(),
2758 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002759 }
2760
reed@google.com4e2b3d32011-04-07 14:18:59 +00002761 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762}
2763
reed@google.come0d9ce82014-04-23 04:00:17 +00002764void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2765 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002766 SkPoint textOffset = SkPoint::Make(0, 0);
2767
halcanary96fcdcc2015-08-27 07:41:13 -07002768 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002769
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002771 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002772 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002773 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002775
reed@google.com4e2b3d32011-04-07 14:18:59 +00002776 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002777}
2778
reed@google.come0d9ce82014-04-23 04:00:17 +00002779void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2780 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002781
2782 SkPoint textOffset = SkPoint::Make(0, constY);
2783
halcanary96fcdcc2015-08-27 07:41:13 -07002784 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002785
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002787 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002788 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002789 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002791
reed@google.com4e2b3d32011-04-07 14:18:59 +00002792 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002793}
2794
reed@google.come0d9ce82014-04-23 04:00:17 +00002795void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2796 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002797 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002798
reed@android.com8a1c16f2008-12-17 15:59:43 +00002799 while (iter.next()) {
2800 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002801 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002802 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002803
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002804 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002805}
2806
reed45561a02016-07-07 12:47:17 -07002807void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2808 const SkRect* cullRect, const SkPaint& paint) {
2809 if (cullRect && this->quickReject(*cullRect)) {
2810 return;
2811 }
2812
2813 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2814
2815 while (iter.next()) {
2816 iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint());
2817 }
2818
2819 LOOPER_END
2820}
2821
fmalita00d5c2c2014-08-21 08:53:26 -07002822void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2823 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002824
fmalita85d5eb92015-03-04 11:20:12 -08002825 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002826 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002827 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002828 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002829 SkRect tmp;
2830 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2831 return;
2832 }
2833 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002834 }
2835
fmalita024f9962015-03-03 19:08:17 -08002836 // We cannot filter in the looper as we normally do, because the paint is
2837 // incomplete at this point (text-related attributes are embedded within blob run paints).
2838 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002839 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002840
fmalita85d5eb92015-03-04 11:20:12 -08002841 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002842
fmalitaaa1b9122014-08-28 14:32:24 -07002843 while (iter.next()) {
2844 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002845 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002846 }
2847
fmalitaaa1b9122014-08-28 14:32:24 -07002848 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002849
2850 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002851}
2852
reed@google.come0d9ce82014-04-23 04:00:17 +00002853// These will become non-virtual, so they always call the (virtual) onDraw... method
2854void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2855 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002856 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reedac095542016-08-04 15:54:41 -07002857 if (byteLength) {
2858 this->onDrawText(text, byteLength, x, y, paint);
2859 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002860}
2861void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2862 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002863 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reedac095542016-08-04 15:54:41 -07002864 if (byteLength) {
2865 this->onDrawPosText(text, byteLength, pos, paint);
2866 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002867}
2868void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2869 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002870 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reedac095542016-08-04 15:54:41 -07002871 if (byteLength) {
2872 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2873 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002874}
2875void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2876 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002877 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reedac095542016-08-04 15:54:41 -07002878 if (byteLength) {
2879 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2880 }
reed@google.come0d9ce82014-04-23 04:00:17 +00002881}
reed45561a02016-07-07 12:47:17 -07002882void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
2883 const SkRect* cullRect, const SkPaint& paint) {
2884 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()");
2885 if (byteLength) {
2886 this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint);
2887 }
2888}
fmalita00d5c2c2014-08-21 08:53:26 -07002889void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2890 const SkPaint& paint) {
reede3b38ce2016-01-08 09:18:44 -08002891 RETURN_ON_NULL(blob);
danakj9881d632014-11-26 12:41:06 -08002892 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
reede3b38ce2016-01-08 09:18:44 -08002893 this->onDrawTextBlob(blob, x, y, paint);
fmalita00d5c2c2014-08-21 08:53:26 -07002894}
reed@google.come0d9ce82014-04-23 04:00:17 +00002895
reed41af9662015-01-05 07:49:08 -08002896void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2897 const SkPoint verts[], const SkPoint texs[],
2898 const SkColor colors[], SkXfermode* xmode,
2899 const uint16_t indices[], int indexCount,
2900 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002901 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002902 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002903
reed@android.com8a1c16f2008-12-17 15:59:43 +00002904 while (iter.next()) {
2905 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002906 colors, xmode, indices, indexCount,
2907 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002908 }
reed@google.com4b226022011-01-11 18:32:13 +00002909
reed@google.com4e2b3d32011-04-07 14:18:59 +00002910 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002911}
2912
dandovb3c9d1c2014-08-12 08:34:29 -07002913void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2914 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002915 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002916 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002917 return;
2918 }
mtklein6cfa73a2014-08-13 13:33:49 -07002919
dandovecfff212014-08-04 10:02:00 -07002920 // Since a patch is always within the convex hull of the control points, we discard it when its
2921 // bounding rectangle is completely outside the current clip.
2922 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002923 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002924 if (this->quickReject(bounds)) {
2925 return;
2926 }
mtklein6cfa73a2014-08-13 13:33:49 -07002927
dandovb3c9d1c2014-08-12 08:34:29 -07002928 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2929}
2930
2931void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2932 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2933
halcanary96fcdcc2015-08-27 07:41:13 -07002934 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002935
dandovecfff212014-08-04 10:02:00 -07002936 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002937 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002938 }
mtklein6cfa73a2014-08-13 13:33:49 -07002939
dandovecfff212014-08-04 10:02:00 -07002940 LOOPER_END
2941}
2942
reeda8db7282015-07-07 10:22:31 -07002943void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
reede3b38ce2016-01-08 09:18:44 -08002944 RETURN_ON_NULL(dr);
2945 if (x || y) {
2946 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2947 this->onDrawDrawable(dr, &matrix);
2948 } else {
2949 this->onDrawDrawable(dr, nullptr);
reed6a070dc2014-11-11 19:36:09 -08002950 }
2951}
2952
reeda8db7282015-07-07 10:22:31 -07002953void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
reede3b38ce2016-01-08 09:18:44 -08002954 RETURN_ON_NULL(dr);
2955 if (matrix && matrix->isIdentity()) {
2956 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002957 }
reede3b38ce2016-01-08 09:18:44 -08002958 this->onDrawDrawable(dr, matrix);
reeda8db7282015-07-07 10:22:31 -07002959}
2960
2961void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2962 SkRect bounds = dr->getBounds();
2963 if (matrix) {
2964 matrix->mapRect(&bounds);
2965 }
2966 if (this->quickReject(bounds)) {
2967 return;
2968 }
2969 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002970}
2971
reed71c3c762015-06-24 10:29:17 -07002972void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2973 const SkColor colors[], int count, SkXfermode::Mode mode,
2974 const SkRect* cull, const SkPaint* paint) {
2975 if (cull && this->quickReject(*cull)) {
2976 return;
2977 }
2978
2979 SkPaint pnt;
2980 if (paint) {
2981 pnt = *paint;
2982 }
halcanary9d524f22016-03-29 09:03:52 -07002983
halcanary96fcdcc2015-08-27 07:41:13 -07002984 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002985 while (iter.next()) {
2986 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2987 }
2988 LOOPER_END
2989}
2990
reedf70b5312016-03-04 16:36:20 -08002991void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
2992 SkASSERT(key);
2993
2994 SkPaint paint;
2995 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
2996 while (iter.next()) {
2997 iter.fDevice->drawAnnotation(iter, rect, key, value);
2998 }
2999 LOOPER_END
3000}
3001
reed@android.com8a1c16f2008-12-17 15:59:43 +00003002//////////////////////////////////////////////////////////////////////////////
3003// These methods are NOT virtual, and therefore must call back into virtual
3004// methods, rather than actually drawing themselves.
3005//////////////////////////////////////////////////////////////////////////////
3006
3007void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00003008 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003009 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003010 SkPaint paint;
3011
3012 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00003013 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003014 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003015 }
3016 this->drawPaint(paint);
3017}
3018
reed@android.com845fdac2009-06-23 03:01:32 +00003019void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08003020 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003021 SkPaint paint;
3022
3023 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00003024 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00003025 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003026 }
3027 this->drawPaint(paint);
3028}
3029
3030void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003031 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003032 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00003033
reed@android.com8a1c16f2008-12-17 15:59:43 +00003034 pt.set(x, y);
3035 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3036}
3037
3038void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08003039 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003040 SkPoint pt;
3041 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00003042
reed@android.com8a1c16f2008-12-17 15:59:43 +00003043 pt.set(x, y);
3044 paint.setColor(color);
3045 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
3046}
3047
3048void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
3049 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003050 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003051 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00003052
reed@android.com8a1c16f2008-12-17 15:59:43 +00003053 pts[0].set(x0, y0);
3054 pts[1].set(x1, y1);
3055 this->drawPoints(kLines_PointMode, 2, pts, paint);
3056}
3057
3058void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
3059 SkScalar right, SkScalar bottom,
3060 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003061 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003062 SkRect r;
3063
3064 r.set(left, top, right, bottom);
3065 this->drawRect(r, paint);
3066}
3067
3068void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
3069 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003070 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003071 if (radius < 0) {
3072 radius = 0;
3073 }
3074
3075 SkRect r;
3076 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00003077 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003078}
3079
3080void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
3081 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003082 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003083 if (rx > 0 && ry > 0) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00003084 SkRRect rrect;
3085 rrect.setRectXY(r, rx, ry);
3086 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003087 } else {
3088 this->drawRect(r, paint);
3089 }
3090}
3091
reed@android.com8a1c16f2008-12-17 15:59:43 +00003092void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
3093 SkScalar sweepAngle, bool useCenter,
3094 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003095 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003096 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
3097 this->drawOval(oval, paint);
3098 } else {
bsalomonac3aa242016-08-19 11:25:19 -07003099 this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003100 }
3101}
3102
3103void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
3104 const SkPath& path, SkScalar hOffset,
3105 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08003106 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003107 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00003108
reed@android.com8a1c16f2008-12-17 15:59:43 +00003109 matrix.setTranslate(hOffset, vOffset);
3110 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
3111}
3112
reed@android.comf76bacf2009-05-13 14:00:33 +00003113///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07003114
3115/**
3116 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
3117 * against the playback cost of recursing into the subpicture to get at its actual ops.
3118 *
3119 * For now we pick a conservatively small value, though measurement (and other heuristics like
3120 * the type of ops contained) may justify changing this value.
3121 */
3122#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07003123
reedd5fa1a42014-08-09 11:08:05 -07003124void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reede3b38ce2016-01-08 09:18:44 -08003125 RETURN_ON_NULL(picture);
3126
reed1c2c4412015-04-30 13:09:24 -07003127 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
reede3b38ce2016-01-08 09:18:44 -08003128 if (matrix && matrix->isIdentity()) {
3129 matrix = nullptr;
3130 }
3131 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
3132 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3133 picture->playback(this);
3134 } else {
3135 this->onDrawPicture(picture, matrix, paint);
reedd5fa1a42014-08-09 11:08:05 -07003136 }
3137}
robertphillips9b14f262014-06-04 05:40:44 -07003138
reedd5fa1a42014-08-09 11:08:05 -07003139void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
3140 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07003141 if (!paint || paint->canComputeFastBounds()) {
3142 SkRect bounds = picture->cullRect();
3143 if (paint) {
3144 paint->computeFastBounds(bounds, &bounds);
3145 }
3146 if (matrix) {
3147 matrix->mapRect(&bounds);
3148 }
3149 if (this->quickReject(bounds)) {
3150 return;
3151 }
3152 }
3153
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003154 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07003155 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003156}
3157
vjiaoblack95302da2016-07-21 10:25:54 -07003158#ifdef SK_EXPERIMENTAL_SHADOWING
3159void SkCanvas::drawShadowedPicture(const SkPicture* picture,
3160 const SkMatrix* matrix,
3161 const SkPaint* paint) {
3162 RETURN_ON_NULL(picture);
3163
3164 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()");
3165
3166 this->onDrawShadowedPicture(picture, matrix, paint);
3167}
3168
3169void SkCanvas::onDrawShadowedPicture(const SkPicture* picture,
3170 const SkMatrix* matrix,
3171 const SkPaint* paint) {
vjiaoblack904527d2016-08-09 09:32:09 -07003172 if (!paint || paint->canComputeFastBounds()) {
3173 SkRect bounds = picture->cullRect();
3174 if (paint) {
3175 paint->computeFastBounds(bounds, &bounds);
3176 }
3177 if (matrix) {
3178 matrix->mapRect(&bounds);
3179 }
3180 if (this->quickReject(bounds)) {
3181 return;
3182 }
3183 }
3184
3185 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
3186
3187 for (int i = 0; i < fLights->numLights(); ++i) {
3188 // skip over ambient lights; they don't cast shadows
3189 // lights that have shadow maps do not need updating (because lights are immutable)
3190
3191 if (SkLights::Light::kAmbient_LightType == fLights->light(i).type() ||
3192 fLights->light(i).getShadowMap() != nullptr) {
3193 continue;
3194 }
3195
3196 // TODO: compute the correct size of the depth map from the light properties
3197 // TODO: maybe add a kDepth_8_SkColorType
3198 // TODO: find actual max depth of picture
3199 SkISize shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize(
3200 fLights->light(i), 255,
3201 picture->cullRect().width(),
3202 picture->cullRect().height());
3203
3204 SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight,
3205 kBGRA_8888_SkColorType,
3206 kOpaque_SkAlphaType);
3207
3208 // Create a new surface (that matches the backend of canvas)
3209 // for each shadow map
3210 sk_sp<SkSurface> surf(this->makeSurface(info));
3211
3212 // Wrap another SPFCanvas around the surface
3213 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3214 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3215
3216 // set the depth map canvas to have the light we're drawing.
3217 SkLights::Builder builder;
3218 builder.add(fLights->light(i));
3219 sk_sp<SkLights> curLight = builder.finish();
3220
3221 depthMapCanvas->setLights(std::move(curLight));
3222 depthMapCanvas->drawPicture(picture);
3223
3224 fLights->light(i).setShadowMap(surf->makeImageSnapshot());
3225 }
3226
3227 sk_sp<SkImage> povDepthMap;
3228 sk_sp<SkImage> diffuseMap;
3229
3230 // TODO: pass the depth to the shader in vertices, or uniforms
3231 // so we don't have to render depth and color separately
3232
3233 // povDepthMap
3234 {
3235 SkLights::Builder builder;
vjiaoblack772b5ee2016-08-12 11:38:47 -07003236 builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
3237 SkVector3::Make(0.0f, 0.0f, 1.0f)));
vjiaoblack904527d2016-08-09 09:32:09 -07003238 sk_sp<SkLights> povLight = builder.finish();
3239
3240 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3241 picture->cullRect().height(),
3242 kBGRA_8888_SkColorType,
3243 kOpaque_SkAlphaType);
3244
3245 // Create a new surface (that matches the backend of canvas)
3246 // to create the povDepthMap
3247 sk_sp<SkSurface> surf(this->makeSurface(info));
3248
3249 // Wrap another SPFCanvas around the surface
3250 sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas =
3251 sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas());
3252
3253 // set the depth map canvas to have the light as the user's POV
3254 depthMapCanvas->setLights(std::move(povLight));
3255
3256 depthMapCanvas->drawPicture(picture);
3257
3258 povDepthMap = surf->makeImageSnapshot();
3259 }
3260
3261 // diffuseMap
3262 {
3263 SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(),
3264 picture->cullRect().height(),
3265 kBGRA_8888_SkColorType,
3266 kOpaque_SkAlphaType);
3267
3268 sk_sp<SkSurface> surf(this->makeSurface(info));
3269 surf->getCanvas()->drawPicture(picture);
3270
3271 diffuseMap = surf->makeImageSnapshot();
3272 }
3273
3274 SkPaint shadowPaint;
3275
3276 sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode,
3277 SkShader::kClamp_TileMode);
3278
3279 sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode,
3280 SkShader::kClamp_TileMode);
3281
3282 sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader),
3283 std::move(diffuseShader),
3284 std::move(fLights),
3285 diffuseMap->width(),
3286 diffuseMap->height());
3287
3288 shadowPaint.setShader(shadowShader);
3289
3290 this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint);
vjiaoblack95302da2016-07-21 10:25:54 -07003291}
3292#endif
3293
reed@android.com8a1c16f2008-12-17 15:59:43 +00003294///////////////////////////////////////////////////////////////////////////////
3295///////////////////////////////////////////////////////////////////////////////
3296
reed3aafe112016-08-18 12:45:34 -07003297SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
bungeman99fe8222015-08-20 07:57:51 -07003298 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00003299
3300 SkASSERT(canvas);
3301
reed3aafe112016-08-18 12:45:34 -07003302 fImpl = new (fStorage) SkDrawIter(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +00003303 fDone = !fImpl->next();
3304}
3305
3306SkCanvas::LayerIter::~LayerIter() {
3307 fImpl->~SkDrawIter();
3308}
3309
3310void SkCanvas::LayerIter::next() {
3311 fDone = !fImpl->next();
3312}
3313
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00003314SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003315 return fImpl->getDevice();
3316}
3317
3318const SkMatrix& SkCanvas::LayerIter::matrix() const {
3319 return fImpl->getMatrix();
3320}
3321
3322const SkPaint& SkCanvas::LayerIter::paint() const {
3323 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07003324 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00003325 paint = &fDefaultPaint;
3326 }
3327 return *paint;
3328}
3329
reed1e7f5e72016-04-27 07:49:17 -07003330const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +00003331int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
3332int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00003333
3334///////////////////////////////////////////////////////////////////////////////
3335
fmalitac3b589a2014-06-05 12:40:07 -07003336SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003337
3338///////////////////////////////////////////////////////////////////////////////
3339
3340static bool supported_for_raster_canvas(const SkImageInfo& info) {
3341 switch (info.alphaType()) {
3342 case kPremul_SkAlphaType:
3343 case kOpaque_SkAlphaType:
3344 break;
3345 default:
3346 return false;
3347 }
3348
3349 switch (info.colorType()) {
3350 case kAlpha_8_SkColorType:
3351 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003352 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003353 break;
3354 default:
3355 return false;
3356 }
3357
3358 return true;
3359}
3360
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003361SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3362 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003363 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003364 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003365
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003366 SkBitmap bitmap;
3367 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003368 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003369 }
halcanary385fe4d2015-08-26 13:07:48 -07003370 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003371}
reedd5fa1a42014-08-09 11:08:05 -07003372
3373///////////////////////////////////////////////////////////////////////////////
3374
3375SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003376 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003377 : fCanvas(canvas)
3378 , fSaveCount(canvas->getSaveCount())
3379{
bsalomon49f085d2014-09-05 13:34:00 -07003380 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003381 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003382 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003383 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003384 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003385 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003386 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003387 canvas->save();
3388 }
mtklein6cfa73a2014-08-13 13:33:49 -07003389
bsalomon49f085d2014-09-05 13:34:00 -07003390 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003391 canvas->concat(*matrix);
3392 }
3393}
3394
3395SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3396 fCanvas->restoreToCount(fSaveCount);
3397}
reede8f30622016-03-23 18:59:25 -07003398
3399#ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3400SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
3401 return this->makeSurface(info, props).release();
3402}
3403#endif