blob: 1d37e584193e83fa0979117b964cc6195ba15d77 [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"
bungemand3ebb482015-08-05 13:57:49 -070013#include "SkDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080015#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkDrawFilter.h"
17#include "SkDrawLooper.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080018#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070019#include "SkImage.h"
reed262a71b2015-12-05 13:07:27 -080020#include "SkImage_Base.h"
21#include "SkMatrixUtils.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000022#include "SkMetaData.h"
reed4c21dc52015-06-25 12:32:03 -070023#include "SkNinePatchIter.h"
reedc83a2972015-07-16 07:40:45 -070024#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070025#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000026#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000027#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080028#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000029#include "SkRRect.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000030#include "SkSmallAllocator.h"
reed@google.com97af1a62012-08-28 12:19:02 +000031#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070032#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000033#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000034#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080035#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070036
37#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000038
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000039#if SK_SUPPORT_GPU
40#include "GrRenderTarget.h"
41#endif
42
reedc83a2972015-07-16 07:40:45 -070043/*
44 * Return true if the drawing this rect would hit every pixels in the canvas.
45 *
46 * Returns false if
47 * - rect does not contain the canvas' bounds
48 * - paint is not fill
49 * - paint would blur or otherwise change the coverage of the rect
50 */
51bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
52 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070053 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
54 (int)kNone_ShaderOverrideOpacity,
55 "need_matching_enums0");
56 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
57 (int)kOpaque_ShaderOverrideOpacity,
58 "need_matching_enums1");
59 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
60 (int)kNotOpaque_ShaderOverrideOpacity,
61 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070062
63 const SkISize size = this->getBaseLayerSize();
64 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
65 if (!this->getClipStack()->quickContains(bounds)) {
66 return false;
67 }
68
69 if (rect) {
70 if (!this->getTotalMatrix().rectStaysRect()) {
71 return false; // conservative
72 }
73
74 SkRect devRect;
75 this->getTotalMatrix().mapRect(&devRect, *rect);
fmalita8c0144c2015-07-22 05:56:16 -070076 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070077 return false;
78 }
79 }
80
81 if (paint) {
82 SkPaint::Style paintStyle = paint->getStyle();
83 if (!(paintStyle == SkPaint::kFill_Style ||
84 paintStyle == SkPaint::kStrokeAndFill_Style)) {
85 return false;
86 }
87 if (paint->getMaskFilter() || paint->getLooper()
88 || paint->getPathEffect() || paint->getImageFilter()) {
89 return false; // conservative
90 }
91 }
92 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
93}
94
95///////////////////////////////////////////////////////////////////////////////////////////////////
96
reedd990e2f2014-12-22 11:58:30 -080097static bool gIgnoreSaveLayerBounds;
98void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
99 gIgnoreSaveLayerBounds = ignore;
100}
101bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
102 return gIgnoreSaveLayerBounds;
103}
104
reed0acf1b42014-12-22 16:12:38 -0800105static bool gTreatSpriteAsBitmap;
106void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
107 gTreatSpriteAsBitmap = spriteAsBitmap;
108}
109bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
110 return gTreatSpriteAsBitmap;
111}
112
reed@google.comda17f752012-08-16 18:27:05 +0000113// experimental for faster tiled drawing...
114//#define SK_ENABLE_CLIP_QUICKREJECT
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +0000115
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116//#define SK_TRACE_SAVERESTORE
117
118#ifdef SK_TRACE_SAVERESTORE
119 static int gLayerCounter;
120 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
121 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
122
123 static int gRecCounter;
124 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
125 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
126
127 static int gCanvasCounter;
128 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
129 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
130#else
131 #define inc_layer()
132 #define dec_layer()
133 #define inc_rec()
134 #define dec_rec()
135 #define inc_canvas()
136 #define dec_canvas()
137#endif
138
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000139typedef SkTLazy<SkPaint> SkLazyPaint;
140
reedc83a2972015-07-16 07:40:45 -0700141void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000142 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700143 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
144 ? SkSurface::kDiscard_ContentChangeMode
145 : SkSurface::kRetain_ContentChangeMode);
146 }
147}
148
149void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
150 ShaderOverrideOpacity overrideOpacity) {
151 if (fSurfaceBase) {
152 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
153 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
154 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
155 // and therefore we don't care which mode we're in.
156 //
157 if (fSurfaceBase->outstandingImageSnapshot()) {
158 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
159 mode = SkSurface::kDiscard_ContentChangeMode;
160 }
161 }
162 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000163 }
164}
165
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167
reed4a8126e2014-09-22 07:29:03 -0700168static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
169 const uint32_t propFlags = props.flags();
170 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
171 flags &= ~SkPaint::kDither_Flag;
172 }
173 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
174 flags &= ~SkPaint::kAntiAlias_Flag;
175 }
176 return flags;
177}
178
179///////////////////////////////////////////////////////////////////////////////
180
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000181/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 The clip/matrix/proc are fields that reflect the top of the save/restore
183 stack. Whenever the canvas changes, it marks a dirty flag, and then before
184 these are used (assuming we're not on a layer) we rebuild these cache
185 values: they reflect the top of the save stack, but translated and clipped
186 by the device's XY offset and bitmap-bounds.
187*/
188struct DeviceCM {
189 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000190 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000191 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000192 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700193 const SkMatrix* fMatrix;
194 SkMatrix fMatrixStorage;
195 const bool fDeviceIsBitmapDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196
reed96e657d2015-03-10 17:30:07 -0700197 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed86a17e72015-05-14 12:25:22 -0700198 bool conservativeRasterClip, bool deviceIsBitmapDevice)
halcanary96fcdcc2015-08-27 07:41:13 -0700199 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700200 , fClip(conservativeRasterClip)
reed61f501f2015-04-29 08:34:00 -0700201 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700202 {
halcanary96fcdcc2015-08-27 07:41:13 -0700203 if (nullptr != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000205 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206 }
reed@google.com4b226022011-01-11 18:32:13 +0000207 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700208 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000209 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000211 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700212 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000213 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214 fDevice->unref();
215 }
halcanary385fe4d2015-08-26 13:07:48 -0700216 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000217 }
reed@google.com4b226022011-01-11 18:32:13 +0000218
mtkleinfeaadee2015-04-08 11:25:48 -0700219 void reset(const SkIRect& bounds) {
220 SkASSERT(!fPaint);
221 SkASSERT(!fNext);
222 SkASSERT(fDevice);
223 fClip.setRect(bounds);
224 }
225
reed@google.com045e62d2011-10-24 12:19:46 +0000226 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
227 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000228 int x = fDevice->getOrigin().x();
229 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230 int width = fDevice->width();
231 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000232
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 if ((x | y) == 0) {
234 fMatrix = &totalMatrix;
235 fClip = totalClip;
236 } else {
237 fMatrixStorage = totalMatrix;
238 fMatrixStorage.postTranslate(SkIntToScalar(-x),
239 SkIntToScalar(-y));
240 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000241
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 totalClip.translate(-x, -y, &fClip);
243 }
244
reed@google.com045e62d2011-10-24 12:19:46 +0000245 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246
247 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000248
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000250 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 SkRegion::kDifference_Op);
252 }
reed@google.com4b226022011-01-11 18:32:13 +0000253
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000254 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
255
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256#ifdef SK_DEBUG
257 if (!fClip.isEmpty()) {
258 SkIRect deviceR;
259 deviceR.set(0, 0, width, height);
260 SkASSERT(deviceR.contains(fClip.getBounds()));
261 }
262#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000263 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264};
265
266/* This is the record we keep for each save/restore level in the stack.
267 Since a level optionally copies the matrix and/or stack, we have pointers
268 for these fields. If the value is copied for this level, the copy is
269 stored in the ...Storage field, and the pointer points to that. If the
270 value is not copied for this level, we ignore ...Storage, and just point
271 at the corresponding value in the previous level in the stack.
272*/
273class SkCanvas::MCRec {
274public:
reed1f836ee2014-07-07 07:49:34 -0700275 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700276 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 /* If there are any layers in the stack, this points to the top-most
278 one that is at or below this level in the stack (so we know what
279 bitmap/device to draw into from this level. This value is NOT
280 reference counted, since the real owner is either our fLayer field,
281 or a previous one in a lower level.)
282 */
reed2ff1fce2014-12-11 07:07:37 -0800283 DeviceCM* fTopLayer;
284 SkRasterClip fRasterClip;
285 SkMatrix fMatrix;
286 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287
reedd9544982014-09-09 18:46:22 -0700288 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700289 fFilter = nullptr;
290 fLayer = nullptr;
291 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800292 fMatrix.reset();
293 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700294
reedd9544982014-09-09 18:46:22 -0700295 // don't bother initializing fNext
296 inc_rec();
297 }
reed2ff1fce2014-12-11 07:07:37 -0800298 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700299 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700300 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700301 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800302 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700303
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 // don't bother initializing fNext
305 inc_rec();
306 }
307 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000308 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700309 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310 dec_rec();
311 }
mtkleinfeaadee2015-04-08 11:25:48 -0700312
313 void reset(const SkIRect& bounds) {
314 SkASSERT(fLayer);
315 SkASSERT(fDeferredSaveCount == 0);
316
317 fMatrix.reset();
318 fRasterClip.setRect(bounds);
319 fLayer->reset(bounds);
320 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321};
322
323class SkDrawIter : public SkDraw {
324public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000325 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000326 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000327 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328 canvas->updateDeviceCMCache();
329
reed687fa1c2015-04-07 08:00:56 -0700330 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000332 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333 }
reed@google.com4b226022011-01-11 18:32:13 +0000334
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 bool next() {
336 // skip over recs with empty clips
337 if (fSkipEmptyClips) {
338 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
339 fCurrLayer = fCurrLayer->fNext;
340 }
341 }
342
reed@google.comf68c5e22012-02-24 16:38:58 +0000343 const DeviceCM* rec = fCurrLayer;
344 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345
346 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000347 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
348 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700350 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700351 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700352 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000354 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355
356 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700357 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000358
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359 return true;
360 }
361 return false;
362 }
reed@google.com4b226022011-01-11 18:32:13 +0000363
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000364 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000365 int getX() const { return fDevice->getOrigin().x(); }
366 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367 const SkMatrix& getMatrix() const { return *fMatrix; }
368 const SkRegion& getClip() const { return *fClip; }
369 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000370
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371private:
372 SkCanvas* fCanvas;
373 const DeviceCM* fCurrLayer;
374 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375 SkBool8 fSkipEmptyClips;
376
377 typedef SkDraw INHERITED;
378};
379
380/////////////////////////////////////////////////////////////////////////////
381
reeddbc3cef2015-04-29 12:18:57 -0700382static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
383 return lazy->isValid() ? lazy->get() : lazy->set(orig);
384}
385
386/**
387 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700388 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700389 */
390static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700391 SkImageFilter* imgf = paint.getImageFilter();
392 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700393 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700394 }
395
396 SkColorFilter* imgCF;
397 if (!imgf->asAColorFilter(&imgCF)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700398 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700399 }
400
401 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700402 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700403 // there is no existing paint colorfilter, so we can just return the imagefilter's
404 return imgCF;
405 }
406
407 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
408 // and we need to combine them into a single colorfilter.
409 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
410 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
reeddbc3cef2015-04-29 12:18:57 -0700411}
412
senorblanco87e066e2015-10-28 11:23:36 -0700413/**
414 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
415 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
416 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
417 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
418 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
419 * conservative "effective" bounds based on the settings in the paint... with one exception. This
420 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
421 * deliberately ignored.
422 */
423static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
424 const SkRect& rawBounds,
425 SkRect* storage) {
426 SkPaint tmpUnfiltered(paint);
427 tmpUnfiltered.setImageFilter(nullptr);
428 if (tmpUnfiltered.canComputeFastBounds()) {
429 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
430 } else {
431 return rawBounds;
432 }
433}
434
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435class AutoDrawLooper {
436public:
senorblanco87e066e2015-10-28 11:23:36 -0700437 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
438 // paint. It's used to determine the size of the offscreen layer for filters.
439 // If null, the clip will be used instead.
reed4a8126e2014-09-22 07:29:03 -0700440 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000441 bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700442 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000443 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700445 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000446 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700447 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000448 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449
reeddbc3cef2015-04-29 12:18:57 -0700450 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
451 if (simplifiedCF) {
452 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
453 paint->setColorFilter(simplifiedCF)->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700454 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700455 fPaint = paint;
456 }
457
458 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700459 /**
460 * We implement ImageFilters for a given draw by creating a layer, then applying the
461 * imagefilter to the pixels of that layer (its backing surface/image), and then
462 * we call restore() to xfer that layer to the main canvas.
463 *
464 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
465 * 2. Generate the src pixels:
466 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
467 * return (fPaint). We then draw the primitive (using srcover) into a cleared
468 * buffer/surface.
469 * 3. Restore the layer created in #1
470 * The imagefilter is passed the buffer/surface from the layer (now filled with the
471 * src pixels of the primitive). It returns a new "filtered" buffer, which we
472 * draw onto the previous layer using the xfermode from the original paint.
473 */
reed@google.com8926b162012-03-23 15:36:36 +0000474 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700475 tmp.setImageFilter(fPaint->getImageFilter());
476 tmp.setXfermode(fPaint->getXfermode());
senorblanco87e066e2015-10-28 11:23:36 -0700477 SkRect storage;
478 if (rawBounds) {
479 // Make rawBounds include all paint outsets except for those due to image filters.
480 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
481 }
senorblanco87e066e2015-10-28 11:23:36 -0700482 (void)canvas->internalSaveLayer(rawBounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
reed76033be2015-03-14 10:54:31 -0700483 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700484 fTempLayerForImageFilter = true;
485 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000486 }
487
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000488 if (SkDrawLooper* looper = paint.getLooper()) {
489 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
490 looper->contextSize());
491 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000492 fIsSimple = false;
493 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700494 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000495 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700496 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000497 }
piotaixrb5fae932014-09-24 13:03:30 -0700498
reed4a8126e2014-09-22 07:29:03 -0700499 uint32_t oldFlags = paint.getFlags();
500 fNewPaintFlags = filter_paint_flags(props, oldFlags);
501 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700502 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700503 paint->setFlags(fNewPaintFlags);
504 fPaint = paint;
505 // if we're not simple, doNext() will take care of calling setFlags()
506 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000507 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000508
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700510 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000511 fCanvas->internalRestore();
512 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000513 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@google.com4e2b3d32011-04-07 14:18:59 +0000516 const SkPaint& paint() const {
517 SkASSERT(fPaint);
518 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000520
reed@google.com129ec222012-05-15 13:24:09 +0000521 bool next(SkDrawFilter::Type drawType) {
522 if (fDone) {
523 return false;
524 } else if (fIsSimple) {
525 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000526 return !fPaint->nothingToDraw();
527 } else {
528 return this->doNext(drawType);
529 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000530 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000531
reed@android.com8a1c16f2008-12-17 15:59:43 +0000532private:
reeddbc3cef2015-04-29 12:18:57 -0700533 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
534 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000535 SkCanvas* fCanvas;
536 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000537 SkDrawFilter* fFilter;
538 const SkPaint* fPaint;
539 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700540 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700541 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000542 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000543 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000544 SkDrawLooper::Context* fLooperContext;
545 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000546
547 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000548};
549
reed@google.com129ec222012-05-15 13:24:09 +0000550bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700551 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000552 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700553 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000554
reeddbc3cef2015-04-29 12:18:57 -0700555 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
556 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700557 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000558
reed5c476fb2015-04-20 08:04:21 -0700559 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700560 paint->setImageFilter(nullptr);
561 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000562 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000563
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000564 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000565 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000566 return false;
567 }
568 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000569 if (!fFilter->filter(paint, drawType)) {
570 fDone = true;
571 return false;
572 }
halcanary96fcdcc2015-08-27 07:41:13 -0700573 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000574 // no looper means we only draw once
575 fDone = true;
576 }
577 }
578 fPaint = paint;
579
580 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000581 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000582 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000583 }
584
585 // call this after any possible paint modifiers
586 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700587 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000588 return false;
589 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000590 return true;
591}
592
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593////////// macros to place around the internal draw calls //////////////////
594
reed262a71b2015-12-05 13:07:27 -0800595#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
596 this->predrawNotify(); \
597 AutoDrawLooper looper(this, fProps, paint, skipLayerForFilter, bounds); \
598 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
599 SkDrawIter iter(this);
600
601
reed@google.com8926b162012-03-23 15:36:36 +0000602#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000603 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700604 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000605 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000606 SkDrawIter iter(this);
607
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000608#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000609 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700610 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000611 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000613
reedc83a2972015-07-16 07:40:45 -0700614#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
615 this->predrawNotify(bounds, &paint, auxOpaque); \
616 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
617 while (looper.next(type)) { \
618 SkDrawIter iter(this);
619
reed@google.com4e2b3d32011-04-07 14:18:59 +0000620#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000621
622////////////////////////////////////////////////////////////////////////////
623
mtkleinfeaadee2015-04-08 11:25:48 -0700624void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
625 this->restoreToCount(1);
626 fCachedLocalClipBounds.setEmpty();
627 fCachedLocalClipBoundsDirty = true;
628 fClipStack->reset();
629 fMCRec->reset(bounds);
630
631 // We're peering through a lot of structs here. Only at this scope do we
632 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
633 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
634}
635
reedd9544982014-09-09 18:46:22 -0700636SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800637 if (device && device->forceConservativeRasterClip()) {
638 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
639 }
640 // Since init() is only called once by our constructors, it is safe to perform this
641 // const-cast.
642 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
643
reed@google.comc0784db2013-12-13 21:16:12 +0000644 fCachedLocalClipBounds.setEmpty();
645 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000646 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000647 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700648 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800649 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700650 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000651
halcanary385fe4d2015-08-26 13:07:48 -0700652 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700653
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700655 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656
reeda499f902015-05-01 09:34:31 -0700657 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
658 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
halcanary96fcdcc2015-08-27 07:41:13 -0700659 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700660
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662
halcanary96fcdcc2015-08-27 07:41:13 -0700663 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000664
reedf92c8662014-08-18 08:02:43 -0700665 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700666 // The root device and the canvas should always have the same pixel geometry
667 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700668 device->onAttachToCanvas(this);
669 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800670 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700671 }
672 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000673}
674
reed@google.comcde92112011-07-06 20:00:52 +0000675SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000676 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700677 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800678 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000679{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000680 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000681
halcanary96fcdcc2015-08-27 07:41:13 -0700682 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000683}
684
reedd9544982014-09-09 18:46:22 -0700685static SkBitmap make_nopixels(int width, int height) {
686 SkBitmap bitmap;
687 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
688 return bitmap;
689}
690
691class SkNoPixelsBitmapDevice : public SkBitmapDevice {
692public:
robertphillipsfcf78292015-06-19 11:49:52 -0700693 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
694 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800695 {
696 this->setOrigin(bounds.x(), bounds.y());
697 }
reedd9544982014-09-09 18:46:22 -0700698
699private:
piotaixrb5fae932014-09-24 13:03:30 -0700700
reedd9544982014-09-09 18:46:22 -0700701 typedef SkBitmapDevice INHERITED;
702};
703
reed96a857e2015-01-25 10:33:58 -0800704SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000705 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800706 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800707 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000708{
709 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700710
halcanary385fe4d2015-08-26 13:07:48 -0700711 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
712 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700713}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000714
reed78e27682014-11-19 08:04:34 -0800715SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700716 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700717 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800718 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700719{
720 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700721
halcanary385fe4d2015-08-26 13:07:48 -0700722 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700723}
724
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000725SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000726 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700727 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800728 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000729{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000730 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700731
reedd9544982014-09-09 18:46:22 -0700732 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000733}
734
robertphillipsfcf78292015-06-19 11:49:52 -0700735SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
736 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700737 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800738 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700739{
740 inc_canvas();
741
742 this->init(device, flags);
743}
744
reed4a8126e2014-09-22 07:29:03 -0700745SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700746 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700747 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800748 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700749{
750 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700751
halcanary385fe4d2015-08-26 13:07:48 -0700752 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700753 this->init(device, kDefault_InitFlags);
754}
reed29c857d2014-09-21 10:25:07 -0700755
reed4a8126e2014-09-22 07:29:03 -0700756SkCanvas::SkCanvas(const SkBitmap& bitmap)
757 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
758 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800759 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700760{
761 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700762
halcanary385fe4d2015-08-26 13:07:48 -0700763 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700764 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000765}
766
767SkCanvas::~SkCanvas() {
768 // free up the contents of our deque
769 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000770
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771 this->internalRestore(); // restore the last, since we're going away
772
halcanary385fe4d2015-08-26 13:07:48 -0700773 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000774
reed@android.com8a1c16f2008-12-17 15:59:43 +0000775 dec_canvas();
776}
777
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}
787
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000788SkMetaData& SkCanvas::getMetaData() {
789 // metadata users are rare, so we lazily allocate it. If that changes we
790 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700791 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000792 fMetaData = new SkMetaData;
793 }
794 return *fMetaData;
795}
796
reed@android.com8a1c16f2008-12-17 15:59:43 +0000797///////////////////////////////////////////////////////////////////////////////
798
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000799void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000800 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000801 if (device) {
802 device->flush();
803 }
804}
805
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000806SkISize SkCanvas::getTopLayerSize() const {
807 SkBaseDevice* d = this->getTopDevice();
808 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
809}
810
811SkIPoint SkCanvas::getTopLayerOrigin() const {
812 SkBaseDevice* d = this->getTopDevice();
813 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
814}
815
816SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000817 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000818 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
819}
820
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000821SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000822 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000823 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824 SkASSERT(rec && rec->fLayer);
825 return rec->fLayer->fDevice;
826}
827
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000828SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000829 if (updateMatrixClip) {
830 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
831 }
reed@google.com9266fed2011-03-30 00:18:03 +0000832 return fMCRec->fTopLayer->fDevice;
833}
834
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000835bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
836 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
837 return false;
838 }
839
840 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700841 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700842 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000843 return false;
844 }
845 weAllocated = true;
846 }
847
reedcf01e312015-05-23 19:14:51 -0700848 SkAutoPixmapUnlock unlocker;
849 if (bitmap->requestLock(&unlocker)) {
850 const SkPixmap& pm = unlocker.pixmap();
851 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
852 return true;
853 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000854 }
855
856 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700857 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000858 }
859 return false;
860}
reed@google.com51df9e32010-12-23 19:29:18 +0000861
bsalomon@google.comc6980972011-11-02 19:57:21 +0000862bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000863 SkIRect r = srcRect;
864 const SkISize size = this->getBaseLayerSize();
865 if (!r.intersect(0, 0, size.width(), size.height())) {
866 bitmap->reset();
867 return false;
868 }
869
reed84825042014-09-02 12:50:45 -0700870 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000871 // bitmap will already be reset.
872 return false;
873 }
874 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
875 bitmap->reset();
876 return false;
877 }
878 return true;
879}
880
reed96472de2014-12-10 09:53:42 -0800881bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000882 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000883 if (!device) {
884 return false;
885 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000886 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800887
reed96472de2014-12-10 09:53:42 -0800888 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
889 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000890 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000891 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000892
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000893 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800894 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000895}
896
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000897bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
898 if (bitmap.getTexture()) {
899 return false;
900 }
reedcf01e312015-05-23 19:14:51 -0700901
902 SkAutoPixmapUnlock unlocker;
903 if (bitmap.requestLock(&unlocker)) {
904 const SkPixmap& pm = unlocker.pixmap();
905 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000906 }
907 return false;
908}
909
910bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
911 int x, int y) {
912 switch (origInfo.colorType()) {
913 case kUnknown_SkColorType:
914 case kIndex_8_SkColorType:
915 return false;
916 default:
917 break;
918 }
halcanary96fcdcc2015-08-27 07:41:13 -0700919 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000920 return false;
921 }
922
923 const SkISize size = this->getBaseLayerSize();
924 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
925 if (!target.intersect(0, 0, size.width(), size.height())) {
926 return false;
927 }
928
929 SkBaseDevice* device = this->getDevice();
930 if (!device) {
931 return false;
932 }
933
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000934 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700935 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000936
937 // if x or y are negative, then we have to adjust pixels
938 if (x > 0) {
939 x = 0;
940 }
941 if (y > 0) {
942 y = 0;
943 }
944 // here x,y are either 0 or negative
945 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
946
reed4af35f32014-06-27 17:47:49 -0700947 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700948 const bool completeOverwrite = info.dimensions() == size;
949 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700950
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000951 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000952 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000953}
reed@google.com51df9e32010-12-23 19:29:18 +0000954
junov@google.com4370aed2012-01-18 16:21:08 +0000955SkCanvas* SkCanvas::canvasForDrawIter() {
956 return this;
957}
958
reed@android.com8a1c16f2008-12-17 15:59:43 +0000959//////////////////////////////////////////////////////////////////////////////
960
reed@android.com8a1c16f2008-12-17 15:59:43 +0000961void SkCanvas::updateDeviceCMCache() {
962 if (fDeviceCMDirty) {
963 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700964 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000966
halcanary96fcdcc2015-08-27 07:41:13 -0700967 if (nullptr == layer->fNext) { // only one layer
968 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000969 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000970 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971 do {
reed687fa1c2015-04-07 08:00:56 -0700972 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700973 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 }
975 fDeviceCMDirty = false;
976 }
977}
978
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979///////////////////////////////////////////////////////////////////////////////
980
reed2ff1fce2014-12-11 07:07:37 -0800981void SkCanvas::checkForDeferredSave() {
982 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800983 this->doSave();
984 }
985}
986
reedf0090cb2014-11-26 08:55:51 -0800987int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800988#ifdef SK_DEBUG
989 int count = 0;
990 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
991 for (;;) {
992 const MCRec* rec = (const MCRec*)iter.next();
993 if (!rec) {
994 break;
995 }
996 count += 1 + rec->fDeferredSaveCount;
997 }
998 SkASSERT(count == fSaveCount);
999#endif
1000 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001001}
1002
1003int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001004 fSaveCount += 1;
1005 fMCRec->fDeferredSaveCount += 1;
1006 return this->getSaveCount() - 1; // return our prev value
1007}
1008
1009void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001010 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001011
1012 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1013 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001014 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001015}
1016
1017void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001018 if (fMCRec->fDeferredSaveCount > 0) {
1019 SkASSERT(fSaveCount > 1);
1020 fSaveCount -= 1;
1021 fMCRec->fDeferredSaveCount -= 1;
1022 } else {
1023 // check for underflow
1024 if (fMCStack.count() > 1) {
1025 this->willRestore();
1026 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001027 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001028 this->internalRestore();
1029 this->didRestore();
1030 }
reedf0090cb2014-11-26 08:55:51 -08001031 }
1032}
1033
1034void SkCanvas::restoreToCount(int count) {
1035 // sanity check
1036 if (count < 1) {
1037 count = 1;
1038 }
mtkleinf0f14112014-12-12 08:46:25 -08001039
reedf0090cb2014-11-26 08:55:51 -08001040 int n = this->getSaveCount() - count;
1041 for (int i = 0; i < n; ++i) {
1042 this->restore();
1043 }
1044}
1045
reed2ff1fce2014-12-11 07:07:37 -08001046void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001047 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001048 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001049 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001050
reed687fa1c2015-04-07 08:00:56 -07001051 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001052}
1053
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001055#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +00001057#else
1058 return true;
1059#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001060}
1061
junov@chromium.orga907ac32012-02-24 21:54:07 +00001062bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -07001063 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001064 SkIRect clipBounds;
1065 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001066 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001067 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001068
reed96e657d2015-03-10 17:30:07 -07001069 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1070
senorblanco87e066e2015-10-28 11:23:36 -07001071// This is a temporary hack, until individual filters can do their own
1072// bloating, when this will be removed.
1073#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
1074 SkRect storage;
1075#endif
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001076 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -07001077 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco87e066e2015-10-28 11:23:36 -07001078#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
1079 if (bounds && imageFilter->canComputeFastBounds()) {
1080 imageFilter->computeFastBounds(*bounds, &storage);
1081 bounds = &storage;
1082 } else {
1083 bounds = nullptr;
1084 }
senorblancodb64af32015-12-09 10:11:43 -08001085#else
1086 if (bounds && !imageFilter->canComputeFastBounds()) {
1087 bounds = nullptr;
1088 }
senorblanco87e066e2015-10-28 11:23:36 -07001089#endif
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001090 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001091 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001092 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001094
reed96e657d2015-03-10 17:30:07 -07001095 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001096 r.roundOut(&ir);
1097 // early exit if the layer's bounds are clipped out
1098 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001099 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -07001100 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001101 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001102 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001103 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001104 }
1105 } else { // no user bounds, so just use the clip
1106 ir = clipBounds;
1107 }
reed180aec42015-03-11 10:39:04 -07001108 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001109
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +00001110 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -07001111 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -07001112 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -07001113 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001114 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001115 }
1116
1117 if (intersection) {
1118 *intersection = ir;
1119 }
1120 return true;
1121}
1122
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001123int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -08001124 if (gIgnoreSaveLayerBounds) {
halcanary96fcdcc2015-08-27 07:41:13 -07001125 bounds = nullptr;
reedd990e2f2014-12-22 11:58:30 -08001126 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001127 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -07001128 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -07001129 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -08001130 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001131}
1132
reed2ff1fce2014-12-11 07:07:37 -08001133int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -08001134 if (gIgnoreSaveLayerBounds) {
halcanary96fcdcc2015-08-27 07:41:13 -07001135 bounds = nullptr;
reedd990e2f2014-12-22 11:58:30 -08001136 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001137 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -07001138 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -07001139 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -08001140 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +00001141}
1142
reed70ee31b2015-12-10 13:44:45 -08001143int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
1144 unsigned flags = kARGB_ClipLayer_SaveFlag | kPreserveLCDText_PrivateSaveFlag;
1145 return this->saveLayer(bounds, paint, (SaveFlags)flags);
1146}
1147
1148
reed2ff1fce2014-12-11 07:07:37 -08001149void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -07001150 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +00001151#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +00001152 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001153#endif
1154
junov@chromium.orga907ac32012-02-24 21:54:07 +00001155 // do this before we create the layer. We don't call the public save() since
1156 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001157 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001158
1159 fDeviceCMDirty = true;
1160
1161 SkIRect ir;
halcanary96fcdcc2015-08-27 07:41:13 -07001162 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : nullptr)) {
reed2ff1fce2014-12-11 07:07:37 -08001163 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001164 }
1165
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001166 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1167 // the clipRectBounds() call above?
1168 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001169 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001170 }
1171
reed76033be2015-03-14 10:54:31 -07001172 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001173 SkPixelGeometry geo = fProps.pixelGeometry();
1174 if (paint) {
reed76033be2015-03-14 10:54:31 -07001175 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001176 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001177 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001178 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001179 }
1180 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001181 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1182 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183
reedb2db8982014-11-13 12:41:02 -08001184 SkBaseDevice* device = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001185 if (nullptr == device) {
reedb2db8982014-11-13 12:41:02 -08001186 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001187 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001188 }
reedb2db8982014-11-13 12:41:02 -08001189
reed61f501f2015-04-29 08:34:00 -07001190 bool forceSpriteOnRestore = false;
1191 {
reed70ee31b2015-12-10 13:44:45 -08001192 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
1193 SkToBool(flags & kPreserveLCDText_PrivateSaveFlag);
reeddaa57bf2015-05-15 10:39:17 -07001194 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001195 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1196 preserveLCDText, false);
reed61f501f2015-04-29 08:34:00 -07001197 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001198 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001199 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001200 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1201 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
halcanary96fcdcc2015-08-27 07:41:13 -07001202 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001203 SkErrorInternals::SetError(kInternalError_SkError,
1204 "Unable to create device for layer.");
1205 return;
1206 }
1207 forceSpriteOnRestore = true;
1208 }
1209 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001210 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001211
reed@google.com6f8f2922011-03-04 22:27:10 +00001212 device->setOrigin(ir.fLeft, ir.fTop);
halcanary385fe4d2015-08-26 13:07:48 -07001213 DeviceCM* layer =
1214 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001215 device->unref();
1216
1217 layer->fNext = fMCRec->fTopLayer;
1218 fMCRec->fLayer = layer;
1219 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001220}
1221
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001222int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1223 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1224}
1225
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1227 SaveFlags flags) {
1228 if (0xFF == alpha) {
halcanary96fcdcc2015-08-27 07:41:13 -07001229 return this->saveLayer(bounds, nullptr, flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230 } else {
1231 SkPaint tmpPaint;
1232 tmpPaint.setAlpha(alpha);
1233 return this->saveLayer(bounds, &tmpPaint, flags);
1234 }
1235}
1236
reed@android.com8a1c16f2008-12-17 15:59:43 +00001237void SkCanvas::internalRestore() {
1238 SkASSERT(fMCStack.count() != 0);
1239
1240 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001241 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242
reed687fa1c2015-04-07 08:00:56 -07001243 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001244
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001245 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246 DeviceCM* layer = fMCRec->fLayer; // may be null
1247 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001248 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249
1250 // now do the normal restore()
1251 fMCRec->~MCRec(); // balanced in save()
1252 fMCStack.pop_back();
1253 fMCRec = (MCRec*)fMCStack.back();
1254
1255 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1256 since if we're being recorded, we don't want to record this (the
1257 recorder will have already recorded the restore).
1258 */
bsalomon49f085d2014-09-05 13:34:00 -07001259 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001261 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001262 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001263 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001264 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001265 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001266 delete layer;
reedb679ca82015-04-07 04:40:48 -07001267 } else {
1268 // we're at the root
reeda499f902015-05-01 09:34:31 -07001269 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001270 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001272 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273}
1274
reed4a8126e2014-09-22 07:29:03 -07001275SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001276 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001277 props = &fProps;
1278 }
1279 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001280}
1281
reed4a8126e2014-09-22 07:29:03 -07001282SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001283 SkBaseDevice* dev = this->getDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001284 return dev ? dev->newSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001285}
1286
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001287SkImageInfo SkCanvas::imageInfo() const {
1288 SkBaseDevice* dev = this->getDevice();
1289 if (dev) {
1290 return dev->imageInfo();
1291 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001292 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001293 }
1294}
1295
1296const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001297 SkPixmap pmap;
1298 if (!this->onPeekPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001299 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001300 }
1301 if (info) {
1302 *info = pmap.info();
1303 }
1304 if (rowBytes) {
1305 *rowBytes = pmap.rowBytes();
1306 }
1307 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001308}
1309
reed884e97c2015-05-26 11:31:54 -07001310bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001311 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001312 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001313}
1314
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001315void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001316 SkPixmap pmap;
1317 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001318 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001319 }
1320 if (info) {
1321 *info = pmap.info();
1322 }
1323 if (rowBytes) {
1324 *rowBytes = pmap.rowBytes();
1325 }
1326 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001327 *origin = this->getTopDevice(false)->getOrigin();
1328 }
reed884e97c2015-05-26 11:31:54 -07001329 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001330}
1331
reed884e97c2015-05-26 11:31:54 -07001332bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001333 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001334 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001335}
1336
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001337SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1338 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -07001339 if (nullptr == fAddr) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001340 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001341 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001342 return; // failure, fAddr is nullptr
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001343 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001344 if (!canvas->readPixels(&fBitmap, 0, 0)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001345 return; // failure, fAddr is nullptr
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001346 }
1347 fAddr = fBitmap.getPixels();
1348 fRowBytes = fBitmap.rowBytes();
1349 }
1350 SkASSERT(fAddr); // success
1351}
1352
1353bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1354 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001355 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001356 } else {
1357 bitmap->reset();
1358 return false;
1359 }
1360}
1361
reed@android.com8a1c16f2008-12-17 15:59:43 +00001362/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001363
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001364void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001365 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001366 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001367 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001368 paint = &tmp;
1369 }
reed@google.com4b226022011-01-11 18:32:13 +00001370
reed@google.com8926b162012-03-23 15:36:36 +00001371 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001372 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001373 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001374 paint = &looper.paint();
1375 SkImageFilter* filter = paint->getImageFilter();
1376 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001377 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001378 SkImageFilter::DeviceProxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001379 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001380 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001381 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001382 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001383 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblancodb64af32015-12-09 10:11:43 -08001384#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001385 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancodb64af32015-12-09 10:11:43 -08001386#else
1387 SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
1388#endif
senorblancobe129b22014-08-08 07:14:35 -07001389 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reedc9b5f8b2015-10-22 13:20:20 -07001390 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(),
1391 SkImageFilter::kApprox_SizeConstraint);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001392 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001393 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001394 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001395 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1396 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001397 }
reed61f501f2015-04-29 08:34:00 -07001398 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001399 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001400 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001401 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001402 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001403 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001404 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001405 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001406}
1407
reed41af9662015-01-05 07:49:08 -08001408void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001409 if (gTreatSpriteAsBitmap) {
1410 this->save();
1411 this->resetMatrix();
1412 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1413 this->restore();
1414 return;
1415 }
1416
danakj9881d632014-11-26 12:41:06 -08001417 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001418 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001419 return;
1420 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001421 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001422
reed@google.com8926b162012-03-23 15:36:36 +00001423 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001424 if (nullptr == paint) {
reed@google.com8926b162012-03-23 15:36:36 +00001425 paint = &tmp;
1426 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001427
reed@google.com8926b162012-03-23 15:36:36 +00001428 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001429
reed@google.com8926b162012-03-23 15:36:36 +00001430 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08001431 const SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1432 iter.fDevice->drawBitmapAsSprite(iter, bitmap, pos.x(), pos.y(), looper.paint());
reed@google.com8926b162012-03-23 15:36:36 +00001433 }
1434 LOOPER_END
1435}
1436
reed@android.com8a1c16f2008-12-17 15:59:43 +00001437/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001438void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001439 SkMatrix m;
1440 m.setTranslate(dx, dy);
1441 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442}
1443
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001444void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001445 SkMatrix m;
1446 m.setScale(sx, sy);
1447 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001448}
1449
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001450void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001451 SkMatrix m;
1452 m.setRotate(degrees);
1453 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001454}
1455
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001456void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001457 SkMatrix m;
1458 m.setSkew(sx, sy);
1459 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001460}
1461
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001462void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001463 if (matrix.isIdentity()) {
1464 return;
1465 }
1466
reed2ff1fce2014-12-11 07:07:37 -08001467 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001469 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001470 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001471
1472 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001473}
1474
reed86a17e72015-05-14 12:25:22 -07001475void SkCanvas::setMatrix(const SkMatrix& matrix) {
1476 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001477 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001478 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001479 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001480 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001481}
1482
reed@android.com8a1c16f2008-12-17 15:59:43 +00001483void SkCanvas::resetMatrix() {
1484 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001485
reed@android.com8a1c16f2008-12-17 15:59:43 +00001486 matrix.reset();
1487 this->setMatrix(matrix);
1488}
1489
1490//////////////////////////////////////////////////////////////////////////////
1491
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001492void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001493 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001494 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1495 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001496}
1497
1498void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001499#ifdef SK_ENABLE_CLIP_QUICKREJECT
1500 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001501 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001502 return false;
1503 }
1504
reed@google.com3b3e8952012-08-16 20:53:31 +00001505 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001506 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001507 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001508
reed687fa1c2015-04-07 08:00:56 -07001509 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001510 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001511 }
1512 }
1513#endif
1514
bsalomonac8cabd2015-11-20 18:53:07 -08001515 if (!fAllowSoftClip) {
1516 edgeStyle = kHard_ClipEdgeStyle;
1517 }
reed90ba0952015-11-20 13:42:47 -08001518
reedc64eff52015-11-21 12:39:45 -08001519 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1520 SkRect devR;
1521 if (rectStaysRect) {
1522 fMCRec->fMatrix.mapRect(&devR, rect);
1523 }
bsalomonac8cabd2015-11-20 18:53:07 -08001524
reedc64eff52015-11-21 12:39:45 -08001525 // Check if we can quick-accept the clip call (and do nothing)
1526 //
1527 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1528 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1529 // might allow lazy save/restores to eliminate entire save/restore blocks.
1530 //
1531 if (SkRegion::kIntersect_Op == op &&
1532 kHard_ClipEdgeStyle == edgeStyle
1533 && rectStaysRect)
1534 {
1535 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1536#if 0
1537 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1538 rect.left(), rect.top(), rect.right(), rect.bottom());
1539#endif
1540 return;
1541 }
1542 }
1543
1544 AutoValidateClip avc(this);
1545
1546 fDeviceCMDirty = true;
1547 fCachedLocalClipBoundsDirty = true;
1548
1549 if (rectStaysRect) {
1550 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1551 fClipStack->clipDevRect(devR, op, isAA);
1552 fMCRec->fRasterClip.op(devR, this->getBaseLayerSize(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001553 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001554 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001555 // and clip against that, since it can handle any matrix. However, to
1556 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1557 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001558 SkPath path;
1559
1560 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001561 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001562 }
1563}
1564
reed73e714e2014-09-04 09:02:23 -07001565static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1566 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001567 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001568}
1569
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001570void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001571 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001572 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001573 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001574 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1575 } else {
1576 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001577 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001578}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001579
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001580void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001581 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001582 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001583 AutoValidateClip avc(this);
1584
1585 fDeviceCMDirty = true;
1586 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001587 if (!fAllowSoftClip) {
1588 edgeStyle = kHard_ClipEdgeStyle;
1589 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001590
reed687fa1c2015-04-07 08:00:56 -07001591 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001592
robertphillips125f19a2015-11-23 09:00:05 -08001593 fMCRec->fRasterClip.op(transformedRRect, this->getBaseLayerSize(), op,
1594 kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001595 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001596 }
1597
1598 SkPath path;
1599 path.addRRect(rrect);
1600 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001601 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001602}
1603
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001604void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001605 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001606 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001607
1608 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1609 SkRect r;
1610 if (path.isRect(&r)) {
1611 this->onClipRect(r, op, edgeStyle);
1612 return;
1613 }
1614 SkRRect rrect;
1615 if (path.isOval(&r)) {
1616 rrect.setOval(r);
1617 this->onClipRRect(rrect, op, edgeStyle);
1618 return;
1619 }
1620 if (path.isRRect(&rrect)) {
1621 this->onClipRRect(rrect, op, edgeStyle);
1622 return;
1623 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001624 }
robertphillips39f05382015-11-24 09:30:12 -08001625
1626 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001627}
1628
1629void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001630#ifdef SK_ENABLE_CLIP_QUICKREJECT
1631 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001632 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001633 return false;
1634 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001635
reed@google.com3b3e8952012-08-16 20:53:31 +00001636 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001637 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001638 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001639
reed687fa1c2015-04-07 08:00:56 -07001640 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001641 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001642 }
1643 }
1644#endif
1645
reed@google.com5c3d1472011-02-22 19:12:23 +00001646 AutoValidateClip avc(this);
1647
reed@android.com8a1c16f2008-12-17 15:59:43 +00001648 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001649 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001650 if (!fAllowSoftClip) {
1651 edgeStyle = kHard_ClipEdgeStyle;
1652 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001653
1654 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001655 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001656
reed@google.comfe701122011-11-08 19:41:23 +00001657 // Check if the transfomation, or the original path itself
1658 // made us empty. Note this can also happen if we contained NaN
1659 // values. computing the bounds detects this, and will set our
1660 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1661 if (devPath.getBounds().isEmpty()) {
1662 // resetting the path will remove any NaN or other wanky values
1663 // that might upset our scan converter.
1664 devPath.reset();
1665 }
1666
reed@google.com5c3d1472011-02-22 19:12:23 +00001667 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001668 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001669
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001670 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001671 bool clipIsAA = getClipStack()->asPath(&devPath);
1672 if (clipIsAA) {
1673 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001674 }
fmalita1a481fe2015-02-04 07:39:34 -08001675
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001676 op = SkRegion::kReplace_Op;
1677 }
1678
reed73e714e2014-09-04 09:02:23 -07001679 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001680}
1681
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001682void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001683 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001684 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001685}
1686
1687void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001688 AutoValidateClip avc(this);
1689
reed@android.com8a1c16f2008-12-17 15:59:43 +00001690 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001691 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001692
reed@google.com5c3d1472011-02-22 19:12:23 +00001693 // todo: signal fClipStack that we have a region, and therefore (I guess)
1694 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001695 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001696
reed1f836ee2014-07-07 07:49:34 -07001697 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001698}
1699
reed@google.com819c9212011-02-23 18:56:55 +00001700#ifdef SK_DEBUG
1701void SkCanvas::validateClip() const {
1702 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001703 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001704 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001705 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001706 return;
1707 }
1708
reed@google.com819c9212011-02-23 18:56:55 +00001709 SkIRect ir;
1710 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001711 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001712
reed687fa1c2015-04-07 08:00:56 -07001713 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001714 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001715 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001716 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001717 case SkClipStack::Element::kRect_Type:
1718 element->getRect().round(&ir);
1719 tmpClip.op(ir, element->getOp());
1720 break;
1721 case SkClipStack::Element::kEmpty_Type:
1722 tmpClip.setEmpty();
1723 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001724 default: {
1725 SkPath path;
1726 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001727 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001728 break;
1729 }
reed@google.com819c9212011-02-23 18:56:55 +00001730 }
1731 }
reed@google.com819c9212011-02-23 18:56:55 +00001732}
1733#endif
1734
reed@google.com90c07ea2012-04-13 13:50:27 +00001735void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001736 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001737 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001738
halcanary96fcdcc2015-08-27 07:41:13 -07001739 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001740 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001741 }
1742}
1743
reed@google.com5c3d1472011-02-22 19:12:23 +00001744///////////////////////////////////////////////////////////////////////////////
1745
reed@google.com754de5f2014-02-24 19:38:20 +00001746bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001747 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001748}
1749
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001750bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001751 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001752}
1753
reed@google.com3b3e8952012-08-16 20:53:31 +00001754bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001755 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001756 return true;
1757
reed1f836ee2014-07-07 07:49:34 -07001758 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001759 return true;
1760 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001761
reed1f836ee2014-07-07 07:49:34 -07001762 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001763 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001764 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001765 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001766 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001767 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001768
reed@android.coma380ae42009-07-21 01:17:02 +00001769 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001770 // TODO: should we use | instead, or compare all 4 at once?
1771 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001772 return true;
1773 }
reed@google.comc0784db2013-12-13 21:16:12 +00001774 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001775 return true;
1776 }
1777 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001778 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001779}
1780
reed@google.com3b3e8952012-08-16 20:53:31 +00001781bool SkCanvas::quickReject(const SkPath& path) const {
1782 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001783}
1784
reed@google.com3b3e8952012-08-16 20:53:31 +00001785bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001786 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001787 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001788 return false;
1789 }
1790
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001791 SkMatrix inverse;
1792 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001793 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001794 if (bounds) {
1795 bounds->setEmpty();
1796 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001797 return false;
1798 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001799
bsalomon49f085d2014-09-05 13:34:00 -07001800 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001801 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001802 // adjust it outwards in case we are antialiasing
1803 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001804
reed@google.com8f4d2302013-12-17 16:44:46 +00001805 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1806 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001807 inverse.mapRect(bounds, r);
1808 }
1809 return true;
1810}
1811
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001812bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001813 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001814 if (clip.isEmpty()) {
1815 if (bounds) {
1816 bounds->setEmpty();
1817 }
1818 return false;
1819 }
1820
bsalomon49f085d2014-09-05 13:34:00 -07001821 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001822 *bounds = clip.getBounds();
1823 }
1824 return true;
1825}
1826
reed@android.com8a1c16f2008-12-17 15:59:43 +00001827const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001828 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001829}
1830
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001831const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001832 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001833}
1834
reed@google.com9c135db2014-03-12 18:28:35 +00001835GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1836 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001837 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001838}
1839
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001840GrContext* SkCanvas::getGrContext() {
1841#if SK_SUPPORT_GPU
1842 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001843 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001844 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001845 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001846 return renderTarget->getContext();
1847 }
1848 }
1849#endif
1850
halcanary96fcdcc2015-08-27 07:41:13 -07001851 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001852
1853}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001854
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001855void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1856 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001857 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001858 if (outer.isEmpty()) {
1859 return;
1860 }
1861 if (inner.isEmpty()) {
1862 this->drawRRect(outer, paint);
1863 return;
1864 }
1865
1866 // We don't have this method (yet), but technically this is what we should
1867 // be able to assert...
1868 // SkASSERT(outer.contains(inner));
1869 //
1870 // For now at least check for containment of bounds
1871 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1872
1873 this->onDrawDRRect(outer, inner, paint);
1874}
1875
reed41af9662015-01-05 07:49:08 -08001876// These need to stop being virtual -- clients need to override the onDraw... versions
1877
1878void SkCanvas::drawPaint(const SkPaint& paint) {
1879 this->onDrawPaint(paint);
1880}
1881
1882void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1883 this->onDrawRect(r, paint);
1884}
1885
1886void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1887 this->onDrawOval(r, paint);
1888}
1889
1890void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1891 this->onDrawRRect(rrect, paint);
1892}
1893
1894void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1895 this->onDrawPoints(mode, count, pts, paint);
1896}
1897
1898void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1899 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1900 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1901 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1902 indices, indexCount, paint);
1903}
1904
1905void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1906 this->onDrawPath(path, paint);
1907}
1908
reeda85d4d02015-05-06 12:56:48 -07001909void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1910 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001911}
1912
reede47829b2015-08-06 10:02:53 -07001913void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1914 const SkPaint* paint, SrcRectConstraint constraint) {
1915 if (dst.isEmpty() || src.isEmpty()) {
1916 return;
1917 }
1918 this->onDrawImageRect(image, &src, dst, paint, constraint);
1919}
reed41af9662015-01-05 07:49:08 -08001920
reed84984ef2015-07-17 07:09:43 -07001921void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1922 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001923 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001924}
1925
reede47829b2015-08-06 10:02:53 -07001926void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1927 SrcRectConstraint constraint) {
1928 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1929 constraint);
1930}
reede47829b2015-08-06 10:02:53 -07001931
reed4c21dc52015-06-25 12:32:03 -07001932void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1933 const SkPaint* paint) {
1934 if (dst.isEmpty()) {
1935 return;
1936 }
1937 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001938 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001939 }
1940 this->onDrawImageNine(image, center, dst, paint);
1941}
1942
reed41af9662015-01-05 07:49:08 -08001943void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001944 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001945 return;
1946 }
reed41af9662015-01-05 07:49:08 -08001947 this->onDrawBitmap(bitmap, dx, dy, paint);
1948}
1949
reede47829b2015-08-06 10:02:53 -07001950void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001951 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001952 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001953 return;
1954 }
reede47829b2015-08-06 10:02:53 -07001955 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001956}
1957
reed84984ef2015-07-17 07:09:43 -07001958void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1959 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001960 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001961}
1962
reede47829b2015-08-06 10:02:53 -07001963void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1964 SrcRectConstraint constraint) {
1965 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1966 constraint);
1967}
reede47829b2015-08-06 10:02:53 -07001968
reed41af9662015-01-05 07:49:08 -08001969void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1970 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001971 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001972 return;
1973 }
reed4c21dc52015-06-25 12:32:03 -07001974 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001975 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001976 }
reed41af9662015-01-05 07:49:08 -08001977 this->onDrawBitmapNine(bitmap, center, dst, paint);
1978}
1979
1980void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001981 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001982 return;
1983 }
reed41af9662015-01-05 07:49:08 -08001984 this->onDrawSprite(bitmap, left, top, paint);
1985}
1986
reed71c3c762015-06-24 10:29:17 -07001987void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1988 const SkColor colors[], int count, SkXfermode::Mode mode,
1989 const SkRect* cull, const SkPaint* paint) {
1990 if (count <= 0) {
1991 return;
1992 }
1993 SkASSERT(atlas);
1994 SkASSERT(xform);
1995 SkASSERT(tex);
1996 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1997}
1998
reede47829b2015-08-06 10:02:53 -07001999void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2000 const SkPaint* paint, SrcRectConstraint constraint) {
2001 if (src) {
2002 this->drawImageRect(image, *src, dst, paint, constraint);
2003 } else {
2004 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2005 dst, paint, constraint);
2006 }
2007}
2008void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2009 const SkPaint* paint, SrcRectConstraint constraint) {
2010 if (src) {
2011 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2012 } else {
2013 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2014 dst, paint, constraint);
2015 }
2016}
2017
reed@android.com8a1c16f2008-12-17 15:59:43 +00002018//////////////////////////////////////////////////////////////////////////////
2019// These are the virtual drawing methods
2020//////////////////////////////////////////////////////////////////////////////
2021
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002022void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002023 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002024 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2025 }
2026}
2027
reed41af9662015-01-05 07:49:08 -08002028void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002029 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002030 this->internalDrawPaint(paint);
2031}
2032
2033void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002034 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002035
2036 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002037 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002038 }
2039
reed@google.com4e2b3d32011-04-07 14:18:59 +00002040 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002041}
2042
reed41af9662015-01-05 07:49:08 -08002043void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2044 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002045 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002046 if ((long)count <= 0) {
2047 return;
2048 }
2049
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002050 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002051 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002052 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002053 // special-case 2 points (common for drawing a single line)
2054 if (2 == count) {
2055 r.set(pts[0], pts[1]);
2056 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002057 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002058 }
senorblanco87e066e2015-10-28 11:23:36 -07002059 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2060 return;
2061 }
2062 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002063 }
reed@google.coma584aed2012-05-16 14:06:02 +00002064
halcanary96fcdcc2015-08-27 07:41:13 -07002065 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002066
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002067 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002068
reed@android.com8a1c16f2008-12-17 15:59:43 +00002069 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002070 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002071 }
reed@google.com4b226022011-01-11 18:32:13 +00002072
reed@google.com4e2b3d32011-04-07 14:18:59 +00002073 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002074}
2075
reed41af9662015-01-05 07:49:08 -08002076void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002077 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002078 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002079 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002080 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002081 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2082 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2083 SkRect tmp(r);
2084 tmp.sort();
2085
senorblanco87e066e2015-10-28 11:23:36 -07002086 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2087 return;
2088 }
2089 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002090 }
reed@google.com4b226022011-01-11 18:32:13 +00002091
reedc83a2972015-07-16 07:40:45 -07002092 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093
2094 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002095 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002096 }
2097
reed@google.com4e2b3d32011-04-07 14:18:59 +00002098 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002099}
2100
reed41af9662015-01-05 07:49:08 -08002101void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002102 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002103 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002104 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002105 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002106 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2107 return;
2108 }
2109 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002110 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002111
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002112 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002113
2114 while (iter.next()) {
2115 iter.fDevice->drawOval(iter, oval, looper.paint());
2116 }
2117
2118 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002119}
2120
reed41af9662015-01-05 07:49:08 -08002121void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002122 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002123 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002124 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002125 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002126 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2127 return;
2128 }
2129 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002130 }
2131
2132 if (rrect.isRect()) {
2133 // call the non-virtual version
2134 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002135 return;
2136 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002137 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002138 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2139 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002140 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002141
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002142 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002143
2144 while (iter.next()) {
2145 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2146 }
2147
2148 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002149}
2150
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002151void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2152 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002153 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002154 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002155 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002156 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2157 return;
2158 }
2159 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002160 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002161
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002162 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002163
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002164 while (iter.next()) {
2165 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2166 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002167
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002168 LOOPER_END
2169}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002170
reed41af9662015-01-05 07:49:08 -08002171void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002172 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002173 if (!path.isFinite()) {
2174 return;
2175 }
2176
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002177 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002178 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002179 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002180 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002181 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2182 return;
2183 }
2184 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002185 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002186
2187 const SkRect& r = path.getBounds();
2188 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002189 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002190 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002191 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002192 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002193 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002194
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002195 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002196
2197 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002198 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002199 }
2200
reed@google.com4e2b3d32011-04-07 14:18:59 +00002201 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002202}
2203
reed262a71b2015-12-05 13:07:27 -08002204bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
2205#ifdef SK_SUPPORT_LEGACY_LAYER_BITMAP_IMAGEFILTERS
2206 return false;
2207#endif
2208
2209 if (!paint.getImageFilter()) {
2210 return false;
2211 }
2212
2213 const SkMatrix& ctm = this->getTotalMatrix();
2214 const unsigned kSubpixelBits = 0; // matching SkDraw::drawBitmap()
2215 if (!SkTreatAsSprite(ctm, w, h, kSubpixelBits)) {
2216 return false;
2217 }
2218
2219 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2220 // Once we can filter and the filter will return a result larger than itself, we should be
2221 // able to remove this constraint.
2222 // skbug.com/4526
2223 //
2224 SkPoint pt;
2225 ctm.mapXY(x, y, &pt);
2226 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2227 return ir.contains(fMCRec->fRasterClip.getBounds());
2228}
2229
reeda85d4d02015-05-06 12:56:48 -07002230void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002231 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002232 SkRect bounds = SkRect::MakeXYWH(x, y,
2233 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002234 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002235 SkRect tmp = bounds;
2236 if (paint) {
2237 paint->computeFastBounds(tmp, &tmp);
2238 }
2239 if (this->quickReject(tmp)) {
2240 return;
2241 }
reeda85d4d02015-05-06 12:56:48 -07002242 }
2243
2244 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002245 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002246 paint = lazy.init();
2247 }
reed262a71b2015-12-05 13:07:27 -08002248
2249 const bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2250 *paint);
2251 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2252
reeda85d4d02015-05-06 12:56:48 -07002253 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002254 const SkPaint& pnt = looper.paint();
2255 if (drawAsSprite && pnt.getImageFilter()) {
2256 SkBitmap bitmap;
2257 if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2258 SkPoint pt;
2259 iter.fMatrix->mapXY(x, y, &pt);
2260 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2261 SkScalarRoundToInt(pt.fX),
2262 SkScalarRoundToInt(pt.fY), pnt);
2263 }
2264 } else {
2265 iter.fDevice->drawImage(iter, image, x, y, pnt);
2266 }
reeda85d4d02015-05-06 12:56:48 -07002267 }
2268
2269 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002270}
2271
reed41af9662015-01-05 07:49:08 -08002272void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002273 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002274 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002275 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002276 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002277 if (paint) {
2278 paint->computeFastBounds(dst, &storage);
2279 }
2280 if (this->quickReject(storage)) {
2281 return;
2282 }
reeda85d4d02015-05-06 12:56:48 -07002283 }
2284 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002285 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002286 paint = lazy.init();
2287 }
2288
senorblancoc41e7e12015-12-07 12:51:30 -08002289 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002290 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002291
2292 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002293 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002294 }
2295
2296 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002297}
2298
reed41af9662015-01-05 07:49:08 -08002299void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002300 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002301 SkDEBUGCODE(bitmap.validate();)
2302
reed33366972015-10-08 09:22:02 -07002303 if (bitmap.drawsNothing()) {
2304 return;
2305 }
2306
2307 SkLazyPaint lazy;
2308 if (nullptr == paint) {
2309 paint = lazy.init();
2310 }
2311
2312 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2313
2314 SkRect storage;
2315 const SkRect* bounds = nullptr;
2316 if (paint->canComputeFastBounds()) {
2317 bitmap.getBounds(&storage);
2318 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002319 SkRect tmp = storage;
2320 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2321 return;
2322 }
2323 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324 }
reed@google.com4b226022011-01-11 18:32:13 +00002325
reed262a71b2015-12-05 13:07:27 -08002326 const bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2327 bitmap.height(), *paint);
2328 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002329
2330 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002331 const SkPaint& pnt = looper.paint();
2332 if (drawAsSprite && pnt.getImageFilter()) {
2333 SkPoint pt;
2334 iter.fMatrix->mapXY(x, y, &pt);
2335 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2336 SkScalarRoundToInt(pt.fX),
2337 SkScalarRoundToInt(pt.fY), pnt);
2338 } else {
2339 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2340 }
reed33366972015-10-08 09:22:02 -07002341 }
reed262a71b2015-12-05 13:07:27 -08002342
reed33366972015-10-08 09:22:02 -07002343 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002344}
2345
reed@google.com9987ec32011-09-07 11:57:52 +00002346// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002347void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002348 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002349 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002350 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002351 return;
2352 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002353
halcanary96fcdcc2015-08-27 07:41:13 -07002354 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002355 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002356 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2357 return;
2358 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002359 }
reed@google.com3d608122011-11-21 15:16:16 +00002360
reed@google.com33535f32012-09-25 15:37:50 +00002361 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002362 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002363 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002364 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002365
senorblancoc41e7e12015-12-07 12:51:30 -08002366 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002367 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002368
reed@google.com33535f32012-09-25 15:37:50 +00002369 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002370 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002371 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002372
reed@google.com33535f32012-09-25 15:37:50 +00002373 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002374}
2375
reed41af9662015-01-05 07:49:08 -08002376void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002377 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002378 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002379 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002380 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002381}
2382
reed4c21dc52015-06-25 12:32:03 -07002383void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2384 const SkPaint* paint) {
2385 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2386
halcanary96fcdcc2015-08-27 07:41:13 -07002387 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002388 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002389 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2390 return;
2391 }
reed@google.com3d608122011-11-21 15:16:16 +00002392 }
reed4c21dc52015-06-25 12:32:03 -07002393
2394 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002395 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002396 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002397 }
reed4c21dc52015-06-25 12:32:03 -07002398
senorblancoc41e7e12015-12-07 12:51:30 -08002399 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002400
2401 while (iter.next()) {
2402 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002403 }
reed4c21dc52015-06-25 12:32:03 -07002404
2405 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002406}
2407
reed41af9662015-01-05 07:49:08 -08002408void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2409 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002410 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002411 SkDEBUGCODE(bitmap.validate();)
2412
halcanary96fcdcc2015-08-27 07:41:13 -07002413 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002414 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002415 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2416 return;
2417 }
reed4c21dc52015-06-25 12:32:03 -07002418 }
2419
2420 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002421 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002422 paint = lazy.init();
2423 }
2424
senorblancoc41e7e12015-12-07 12:51:30 -08002425 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002426
2427 while (iter.next()) {
2428 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2429 }
2430
2431 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002432}
2433
reed@google.comf67e4cf2011-03-15 20:56:58 +00002434class SkDeviceFilteredPaint {
2435public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002436 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002437 uint32_t filteredFlags = device->filterTextFlags(paint);
2438 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002439 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002440 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002441 fPaint = newPaint;
2442 } else {
2443 fPaint = &paint;
2444 }
2445 }
2446
reed@google.comf67e4cf2011-03-15 20:56:58 +00002447 const SkPaint& paint() const { return *fPaint; }
2448
2449private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002450 const SkPaint* fPaint;
2451 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002452};
2453
bungeman@google.com52c748b2011-08-22 21:30:43 +00002454void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2455 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002456 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002457 draw.fDevice->drawRect(draw, r, paint);
2458 } else {
2459 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002460 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002461 draw.fDevice->drawRect(draw, r, p);
2462 }
2463}
2464
2465void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2466 const char text[], size_t byteLength,
2467 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002468 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002469
2470 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002471 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002472 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002473 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002474 return;
2475 }
2476
2477 SkScalar width = 0;
2478 SkPoint start;
2479
2480 start.set(0, 0); // to avoid warning
2481 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2482 SkPaint::kStrikeThruText_Flag)) {
2483 width = paint.measureText(text, byteLength);
2484
2485 SkScalar offsetX = 0;
2486 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2487 offsetX = SkScalarHalf(width);
2488 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2489 offsetX = width;
2490 }
2491 start.set(x - offsetX, y);
2492 }
2493
2494 if (0 == width) {
2495 return;
2496 }
2497
2498 uint32_t flags = paint.getFlags();
2499
2500 if (flags & (SkPaint::kUnderlineText_Flag |
2501 SkPaint::kStrikeThruText_Flag)) {
2502 SkScalar textSize = paint.getTextSize();
2503 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2504 SkRect r;
2505
2506 r.fLeft = start.fX;
2507 r.fRight = start.fX + width;
2508
2509 if (flags & SkPaint::kUnderlineText_Flag) {
2510 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2511 start.fY);
2512 r.fTop = offset;
2513 r.fBottom = offset + height;
2514 DrawRect(draw, paint, r, textSize);
2515 }
2516 if (flags & SkPaint::kStrikeThruText_Flag) {
2517 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2518 start.fY);
2519 r.fTop = offset;
2520 r.fBottom = offset + height;
2521 DrawRect(draw, paint, r, textSize);
2522 }
2523 }
2524}
2525
reed@google.come0d9ce82014-04-23 04:00:17 +00002526void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2527 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002528 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002529
2530 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002531 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002532 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002533 DrawTextDecorations(iter, dfp.paint(),
2534 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002535 }
2536
reed@google.com4e2b3d32011-04-07 14:18:59 +00002537 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002538}
2539
reed@google.come0d9ce82014-04-23 04:00:17 +00002540void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2541 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002542 SkPoint textOffset = SkPoint::Make(0, 0);
2543
halcanary96fcdcc2015-08-27 07:41:13 -07002544 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002545
reed@android.com8a1c16f2008-12-17 15:59:43 +00002546 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002547 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002548 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002549 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002550 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002551
reed@google.com4e2b3d32011-04-07 14:18:59 +00002552 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002553}
2554
reed@google.come0d9ce82014-04-23 04:00:17 +00002555void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2556 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002557
2558 SkPoint textOffset = SkPoint::Make(0, constY);
2559
halcanary96fcdcc2015-08-27 07:41:13 -07002560 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002561
reed@android.com8a1c16f2008-12-17 15:59:43 +00002562 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002563 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002564 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002565 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002566 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002567
reed@google.com4e2b3d32011-04-07 14:18:59 +00002568 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002569}
2570
reed@google.come0d9ce82014-04-23 04:00:17 +00002571void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2572 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002573 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002574
reed@android.com8a1c16f2008-12-17 15:59:43 +00002575 while (iter.next()) {
2576 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002577 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002578 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002579
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002580 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002581}
2582
fmalita00d5c2c2014-08-21 08:53:26 -07002583void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2584 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002585
fmalita85d5eb92015-03-04 11:20:12 -08002586 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002587 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002588 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002589 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002590 SkRect tmp;
2591 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2592 return;
2593 }
2594 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002595 }
2596
fmalita024f9962015-03-03 19:08:17 -08002597 // We cannot filter in the looper as we normally do, because the paint is
2598 // incomplete at this point (text-related attributes are embedded within blob run paints).
2599 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002600 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002601
fmalita85d5eb92015-03-04 11:20:12 -08002602 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002603
fmalitaaa1b9122014-08-28 14:32:24 -07002604 while (iter.next()) {
2605 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002606 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002607 }
2608
fmalitaaa1b9122014-08-28 14:32:24 -07002609 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002610
2611 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002612}
2613
reed@google.come0d9ce82014-04-23 04:00:17 +00002614// These will become non-virtual, so they always call the (virtual) onDraw... method
2615void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2616 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002617 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002618 this->onDrawText(text, byteLength, x, y, paint);
2619}
2620void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2621 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002622 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002623 this->onDrawPosText(text, byteLength, pos, paint);
2624}
2625void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2626 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002627 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002628 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2629}
2630void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2631 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002632 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002633 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2634}
fmalita00d5c2c2014-08-21 08:53:26 -07002635void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2636 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002637 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002638 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002639 this->onDrawTextBlob(blob, x, y, paint);
2640 }
2641}
reed@google.come0d9ce82014-04-23 04:00:17 +00002642
reed41af9662015-01-05 07:49:08 -08002643void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2644 const SkPoint verts[], const SkPoint texs[],
2645 const SkColor colors[], SkXfermode* xmode,
2646 const uint16_t indices[], int indexCount,
2647 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002648 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002649 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002650
reed@android.com8a1c16f2008-12-17 15:59:43 +00002651 while (iter.next()) {
2652 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002653 colors, xmode, indices, indexCount,
2654 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002655 }
reed@google.com4b226022011-01-11 18:32:13 +00002656
reed@google.com4e2b3d32011-04-07 14:18:59 +00002657 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002658}
2659
dandovb3c9d1c2014-08-12 08:34:29 -07002660void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2661 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002662 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002663 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002664 return;
2665 }
mtklein6cfa73a2014-08-13 13:33:49 -07002666
dandovecfff212014-08-04 10:02:00 -07002667 // Since a patch is always within the convex hull of the control points, we discard it when its
2668 // bounding rectangle is completely outside the current clip.
2669 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002670 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002671 if (this->quickReject(bounds)) {
2672 return;
2673 }
mtklein6cfa73a2014-08-13 13:33:49 -07002674
dandovb3c9d1c2014-08-12 08:34:29 -07002675 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2676}
2677
2678void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2679 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2680
halcanary96fcdcc2015-08-27 07:41:13 -07002681 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002682
dandovecfff212014-08-04 10:02:00 -07002683 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002684 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002685 }
mtklein6cfa73a2014-08-13 13:33:49 -07002686
dandovecfff212014-08-04 10:02:00 -07002687 LOOPER_END
2688}
2689
reeda8db7282015-07-07 10:22:31 -07002690void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2691 if (dr) {
2692 if (x || y) {
2693 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2694 this->onDrawDrawable(dr, &matrix);
2695 } else {
halcanary96fcdcc2015-08-27 07:41:13 -07002696 this->onDrawDrawable(dr, nullptr);
reeda8db7282015-07-07 10:22:31 -07002697 }
reed6a070dc2014-11-11 19:36:09 -08002698 }
2699}
2700
reeda8db7282015-07-07 10:22:31 -07002701void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2702 if (dr) {
2703 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002704 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002705 }
2706 this->onDrawDrawable(dr, matrix);
2707 }
2708}
2709
2710void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2711 SkRect bounds = dr->getBounds();
2712 if (matrix) {
2713 matrix->mapRect(&bounds);
2714 }
2715 if (this->quickReject(bounds)) {
2716 return;
2717 }
2718 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002719}
2720
reed71c3c762015-06-24 10:29:17 -07002721void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2722 const SkColor colors[], int count, SkXfermode::Mode mode,
2723 const SkRect* cull, const SkPaint* paint) {
2724 if (cull && this->quickReject(*cull)) {
2725 return;
2726 }
2727
2728 SkPaint pnt;
2729 if (paint) {
2730 pnt = *paint;
2731 }
2732
halcanary96fcdcc2015-08-27 07:41:13 -07002733 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002734 while (iter.next()) {
2735 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2736 }
2737 LOOPER_END
2738}
2739
reed@android.com8a1c16f2008-12-17 15:59:43 +00002740//////////////////////////////////////////////////////////////////////////////
2741// These methods are NOT virtual, and therefore must call back into virtual
2742// methods, rather than actually drawing themselves.
2743//////////////////////////////////////////////////////////////////////////////
2744
2745void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002746 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002747 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002748 SkPaint paint;
2749
2750 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002751 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002752 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002753 }
2754 this->drawPaint(paint);
2755}
2756
reed@android.com845fdac2009-06-23 03:01:32 +00002757void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002758 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002759 SkPaint paint;
2760
2761 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002762 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002763 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002764 }
2765 this->drawPaint(paint);
2766}
2767
2768void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002769 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002770 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002771
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772 pt.set(x, y);
2773 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2774}
2775
2776void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002777 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002778 SkPoint pt;
2779 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002780
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 pt.set(x, y);
2782 paint.setColor(color);
2783 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2784}
2785
2786void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2787 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002788 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002789 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002790
reed@android.com8a1c16f2008-12-17 15:59:43 +00002791 pts[0].set(x0, y0);
2792 pts[1].set(x1, y1);
2793 this->drawPoints(kLines_PointMode, 2, pts, paint);
2794}
2795
2796void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2797 SkScalar right, SkScalar bottom,
2798 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002799 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002800 SkRect r;
2801
2802 r.set(left, top, right, bottom);
2803 this->drawRect(r, paint);
2804}
2805
2806void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2807 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002808 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809 if (radius < 0) {
2810 radius = 0;
2811 }
2812
2813 SkRect r;
2814 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002815 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002816}
2817
2818void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2819 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002820 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002821 if (rx > 0 && ry > 0) {
2822 if (paint.canComputeFastBounds()) {
2823 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002824 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002825 return;
2826 }
2827 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002828 SkRRect rrect;
2829 rrect.setRectXY(r, rx, ry);
2830 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002831 } else {
2832 this->drawRect(r, paint);
2833 }
2834}
2835
reed@android.com8a1c16f2008-12-17 15:59:43 +00002836void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2837 SkScalar sweepAngle, bool useCenter,
2838 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002839 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002840 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2841 this->drawOval(oval, paint);
2842 } else {
2843 SkPath path;
2844 if (useCenter) {
2845 path.moveTo(oval.centerX(), oval.centerY());
2846 }
2847 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2848 if (useCenter) {
2849 path.close();
2850 }
2851 this->drawPath(path, paint);
2852 }
2853}
2854
2855void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2856 const SkPath& path, SkScalar hOffset,
2857 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002858 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002859 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002860
reed@android.com8a1c16f2008-12-17 15:59:43 +00002861 matrix.setTranslate(hOffset, vOffset);
2862 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2863}
2864
reed@android.comf76bacf2009-05-13 14:00:33 +00002865///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002866
2867/**
2868 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2869 * against the playback cost of recursing into the subpicture to get at its actual ops.
2870 *
2871 * For now we pick a conservatively small value, though measurement (and other heuristics like
2872 * the type of ops contained) may justify changing this value.
2873 */
2874#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002875
reedd5fa1a42014-08-09 11:08:05 -07002876void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002877 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002878 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002879 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002880 matrix = nullptr;
reedd5fa1a42014-08-09 11:08:05 -07002881 }
reed1c2c4412015-04-30 13:09:24 -07002882 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2883 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2884 picture->playback(this);
2885 } else {
2886 this->onDrawPicture(picture, matrix, paint);
2887 }
reedd5fa1a42014-08-09 11:08:05 -07002888 }
2889}
robertphillips9b14f262014-06-04 05:40:44 -07002890
reedd5fa1a42014-08-09 11:08:05 -07002891void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2892 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002893 if (!paint || paint->canComputeFastBounds()) {
2894 SkRect bounds = picture->cullRect();
2895 if (paint) {
2896 paint->computeFastBounds(bounds, &bounds);
2897 }
2898 if (matrix) {
2899 matrix->mapRect(&bounds);
2900 }
2901 if (this->quickReject(bounds)) {
2902 return;
2903 }
2904 }
2905
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002906 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002907 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002908 // Canvas has to first give the device the opportunity to render
2909 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002910 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002911 return; // the device has rendered the entire picture
2912 }
2913 }
2914
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002915 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002916 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002917}
2918
reed@android.com8a1c16f2008-12-17 15:59:43 +00002919///////////////////////////////////////////////////////////////////////////////
2920///////////////////////////////////////////////////////////////////////////////
2921
2922SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002923 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002924
2925 SkASSERT(canvas);
2926
2927 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2928 fDone = !fImpl->next();
2929}
2930
2931SkCanvas::LayerIter::~LayerIter() {
2932 fImpl->~SkDrawIter();
2933}
2934
2935void SkCanvas::LayerIter::next() {
2936 fDone = !fImpl->next();
2937}
2938
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002939SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002940 return fImpl->getDevice();
2941}
2942
2943const SkMatrix& SkCanvas::LayerIter::matrix() const {
2944 return fImpl->getMatrix();
2945}
2946
2947const SkPaint& SkCanvas::LayerIter::paint() const {
2948 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002949 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002950 paint = &fDefaultPaint;
2951 }
2952 return *paint;
2953}
2954
2955const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2956int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2957int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002958
2959///////////////////////////////////////////////////////////////////////////////
2960
fmalitac3b589a2014-06-05 12:40:07 -07002961SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002962
2963///////////////////////////////////////////////////////////////////////////////
2964
2965static bool supported_for_raster_canvas(const SkImageInfo& info) {
2966 switch (info.alphaType()) {
2967 case kPremul_SkAlphaType:
2968 case kOpaque_SkAlphaType:
2969 break;
2970 default:
2971 return false;
2972 }
2973
2974 switch (info.colorType()) {
2975 case kAlpha_8_SkColorType:
2976 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002977 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002978 break;
2979 default:
2980 return false;
2981 }
2982
2983 return true;
2984}
2985
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002986SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2987 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002988 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002989 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002990
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002991 SkBitmap bitmap;
2992 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002993 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002994 }
halcanary385fe4d2015-08-26 13:07:48 -07002995 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002996}
reedd5fa1a42014-08-09 11:08:05 -07002997
2998///////////////////////////////////////////////////////////////////////////////
2999
3000SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003001 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003002 : fCanvas(canvas)
3003 , fSaveCount(canvas->getSaveCount())
3004{
bsalomon49f085d2014-09-05 13:34:00 -07003005 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003006 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003007 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003008 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003009 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003010 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003011 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003012 canvas->save();
3013 }
mtklein6cfa73a2014-08-13 13:33:49 -07003014
bsalomon49f085d2014-09-05 13:34:00 -07003015 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003016 canvas->concat(*matrix);
3017 }
3018}
3019
3020SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3021 fCanvas->restoreToCount(fSaveCount);
3022}