blob: 09fef0bbed2d2d7eb35d4f49d72fc5ab0801d61b [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
robertphillips7354a4b2015-12-16 05:08:27 -080040#include "GrContext.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000041#include "GrRenderTarget.h"
robertphillips7354a4b2015-12-16 05:08:27 -080042#include "SkGr.h"
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000043#endif
44
reedc83a2972015-07-16 07:40:45 -070045/*
46 * Return true if the drawing this rect would hit every pixels in the canvas.
47 *
48 * Returns false if
49 * - rect does not contain the canvas' bounds
50 * - paint is not fill
51 * - paint would blur or otherwise change the coverage of the rect
52 */
53bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
54 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070055 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
56 (int)kNone_ShaderOverrideOpacity,
57 "need_matching_enums0");
58 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
59 (int)kOpaque_ShaderOverrideOpacity,
60 "need_matching_enums1");
61 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
62 (int)kNotOpaque_ShaderOverrideOpacity,
63 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070064
65 const SkISize size = this->getBaseLayerSize();
66 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
67 if (!this->getClipStack()->quickContains(bounds)) {
68 return false;
69 }
70
71 if (rect) {
72 if (!this->getTotalMatrix().rectStaysRect()) {
73 return false; // conservative
74 }
75
76 SkRect devRect;
77 this->getTotalMatrix().mapRect(&devRect, *rect);
fmalita8c0144c2015-07-22 05:56:16 -070078 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070079 return false;
80 }
81 }
82
83 if (paint) {
84 SkPaint::Style paintStyle = paint->getStyle();
85 if (!(paintStyle == SkPaint::kFill_Style ||
86 paintStyle == SkPaint::kStrokeAndFill_Style)) {
87 return false;
88 }
89 if (paint->getMaskFilter() || paint->getLooper()
90 || paint->getPathEffect() || paint->getImageFilter()) {
91 return false; // conservative
92 }
93 }
94 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
95}
96
97///////////////////////////////////////////////////////////////////////////////////////////////////
98
reedd990e2f2014-12-22 11:58:30 -080099static bool gIgnoreSaveLayerBounds;
100void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
101 gIgnoreSaveLayerBounds = ignore;
102}
103bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
104 return gIgnoreSaveLayerBounds;
105}
106
reed0acf1b42014-12-22 16:12:38 -0800107static bool gTreatSpriteAsBitmap;
108void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
109 gTreatSpriteAsBitmap = spriteAsBitmap;
110}
111bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
112 return gTreatSpriteAsBitmap;
113}
114
reed@google.comda17f752012-08-16 18:27:05 +0000115// experimental for faster tiled drawing...
116//#define SK_ENABLE_CLIP_QUICKREJECT
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +0000117
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118//#define SK_TRACE_SAVERESTORE
119
120#ifdef SK_TRACE_SAVERESTORE
121 static int gLayerCounter;
122 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
123 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
124
125 static int gRecCounter;
126 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
127 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
128
129 static int gCanvasCounter;
130 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
131 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
132#else
133 #define inc_layer()
134 #define dec_layer()
135 #define inc_rec()
136 #define dec_rec()
137 #define inc_canvas()
138 #define dec_canvas()
139#endif
140
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000141typedef SkTLazy<SkPaint> SkLazyPaint;
142
reedc83a2972015-07-16 07:40:45 -0700143void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000144 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700145 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
146 ? SkSurface::kDiscard_ContentChangeMode
147 : SkSurface::kRetain_ContentChangeMode);
148 }
149}
150
151void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
152 ShaderOverrideOpacity overrideOpacity) {
153 if (fSurfaceBase) {
154 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
155 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
156 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
157 // and therefore we don't care which mode we're in.
158 //
159 if (fSurfaceBase->outstandingImageSnapshot()) {
160 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
161 mode = SkSurface::kDiscard_ContentChangeMode;
162 }
163 }
164 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000165 }
166}
167
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169
reed4a8126e2014-09-22 07:29:03 -0700170static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
171 const uint32_t propFlags = props.flags();
172 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
173 flags &= ~SkPaint::kDither_Flag;
174 }
175 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
176 flags &= ~SkPaint::kAntiAlias_Flag;
177 }
178 return flags;
179}
180
181///////////////////////////////////////////////////////////////////////////////
182
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000183/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 The clip/matrix/proc are fields that reflect the top of the save/restore
185 stack. Whenever the canvas changes, it marks a dirty flag, and then before
186 these are used (assuming we're not on a layer) we rebuild these cache
187 values: they reflect the top of the save stack, but translated and clipped
188 by the device's XY offset and bitmap-bounds.
189*/
190struct DeviceCM {
191 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000192 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000193 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000194 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700195 const SkMatrix* fMatrix;
196 SkMatrix fMatrixStorage;
197 const bool fDeviceIsBitmapDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198
reed96e657d2015-03-10 17:30:07 -0700199 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed86a17e72015-05-14 12:25:22 -0700200 bool conservativeRasterClip, bool deviceIsBitmapDevice)
halcanary96fcdcc2015-08-27 07:41:13 -0700201 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700202 , fClip(conservativeRasterClip)
reed61f501f2015-04-29 08:34:00 -0700203 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700204 {
halcanary96fcdcc2015-08-27 07:41:13 -0700205 if (nullptr != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000207 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 }
reed@google.com4b226022011-01-11 18:32:13 +0000209 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700210 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000211 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000213 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700214 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000215 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 fDevice->unref();
217 }
halcanary385fe4d2015-08-26 13:07:48 -0700218 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000219 }
reed@google.com4b226022011-01-11 18:32:13 +0000220
mtkleinfeaadee2015-04-08 11:25:48 -0700221 void reset(const SkIRect& bounds) {
222 SkASSERT(!fPaint);
223 SkASSERT(!fNext);
224 SkASSERT(fDevice);
225 fClip.setRect(bounds);
226 }
227
reed@google.com045e62d2011-10-24 12:19:46 +0000228 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
229 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000230 int x = fDevice->getOrigin().x();
231 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 int width = fDevice->width();
233 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000234
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235 if ((x | y) == 0) {
236 fMatrix = &totalMatrix;
237 fClip = totalClip;
238 } else {
239 fMatrixStorage = totalMatrix;
240 fMatrixStorage.postTranslate(SkIntToScalar(-x),
241 SkIntToScalar(-y));
242 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000243
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 totalClip.translate(-x, -y, &fClip);
245 }
246
reed@google.com045e62d2011-10-24 12:19:46 +0000247 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248
249 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000250
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000252 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 SkRegion::kDifference_Op);
254 }
reed@google.com4b226022011-01-11 18:32:13 +0000255
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000256 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
257
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258#ifdef SK_DEBUG
259 if (!fClip.isEmpty()) {
260 SkIRect deviceR;
261 deviceR.set(0, 0, width, height);
262 SkASSERT(deviceR.contains(fClip.getBounds()));
263 }
264#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000265 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266};
267
268/* This is the record we keep for each save/restore level in the stack.
269 Since a level optionally copies the matrix and/or stack, we have pointers
270 for these fields. If the value is copied for this level, the copy is
271 stored in the ...Storage field, and the pointer points to that. If the
272 value is not copied for this level, we ignore ...Storage, and just point
273 at the corresponding value in the previous level in the stack.
274*/
275class SkCanvas::MCRec {
276public:
reed1f836ee2014-07-07 07:49:34 -0700277 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700278 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 /* If there are any layers in the stack, this points to the top-most
280 one that is at or below this level in the stack (so we know what
281 bitmap/device to draw into from this level. This value is NOT
282 reference counted, since the real owner is either our fLayer field,
283 or a previous one in a lower level.)
284 */
reed2ff1fce2014-12-11 07:07:37 -0800285 DeviceCM* fTopLayer;
286 SkRasterClip fRasterClip;
287 SkMatrix fMatrix;
288 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289
reedd9544982014-09-09 18:46:22 -0700290 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700291 fFilter = nullptr;
292 fLayer = nullptr;
293 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800294 fMatrix.reset();
295 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700296
reedd9544982014-09-09 18:46:22 -0700297 // don't bother initializing fNext
298 inc_rec();
299 }
reed2ff1fce2014-12-11 07:07:37 -0800300 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700301 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700302 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700303 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800304 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700305
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306 // don't bother initializing fNext
307 inc_rec();
308 }
309 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000310 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700311 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312 dec_rec();
313 }
mtkleinfeaadee2015-04-08 11:25:48 -0700314
315 void reset(const SkIRect& bounds) {
316 SkASSERT(fLayer);
317 SkASSERT(fDeferredSaveCount == 0);
318
319 fMatrix.reset();
320 fRasterClip.setRect(bounds);
321 fLayer->reset(bounds);
322 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323};
324
325class SkDrawIter : public SkDraw {
326public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000327 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000328 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000329 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330 canvas->updateDeviceCMCache();
331
reed687fa1c2015-04-07 08:00:56 -0700332 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000334 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 }
reed@google.com4b226022011-01-11 18:32:13 +0000336
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 bool next() {
338 // skip over recs with empty clips
339 if (fSkipEmptyClips) {
340 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
341 fCurrLayer = fCurrLayer->fNext;
342 }
343 }
344
reed@google.comf68c5e22012-02-24 16:38:58 +0000345 const DeviceCM* rec = fCurrLayer;
346 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347
348 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000349 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
350 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700352 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700353 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700354 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000356 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357
358 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700359 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000360
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 return true;
362 }
363 return false;
364 }
reed@google.com4b226022011-01-11 18:32:13 +0000365
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000366 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000367 int getX() const { return fDevice->getOrigin().x(); }
368 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 const SkMatrix& getMatrix() const { return *fMatrix; }
370 const SkRegion& getClip() const { return *fClip; }
371 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000372
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373private:
374 SkCanvas* fCanvas;
375 const DeviceCM* fCurrLayer;
376 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377 SkBool8 fSkipEmptyClips;
378
379 typedef SkDraw INHERITED;
380};
381
382/////////////////////////////////////////////////////////////////////////////
383
reeddbc3cef2015-04-29 12:18:57 -0700384static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
385 return lazy->isValid() ? lazy->get() : lazy->set(orig);
386}
387
388/**
389 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700390 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700391 */
392static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700393 SkImageFilter* imgf = paint.getImageFilter();
394 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700395 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700396 }
397
398 SkColorFilter* imgCF;
399 if (!imgf->asAColorFilter(&imgCF)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700400 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700401 }
402
403 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700404 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700405 // there is no existing paint colorfilter, so we can just return the imagefilter's
406 return imgCF;
407 }
408
409 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
410 // and we need to combine them into a single colorfilter.
411 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
412 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
reeddbc3cef2015-04-29 12:18:57 -0700413}
414
senorblanco87e066e2015-10-28 11:23:36 -0700415/**
416 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
417 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
418 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
419 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
420 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
421 * conservative "effective" bounds based on the settings in the paint... with one exception. This
422 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
423 * deliberately ignored.
424 */
425static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
426 const SkRect& rawBounds,
427 SkRect* storage) {
428 SkPaint tmpUnfiltered(paint);
429 tmpUnfiltered.setImageFilter(nullptr);
430 if (tmpUnfiltered.canComputeFastBounds()) {
431 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
432 } else {
433 return rawBounds;
434 }
435}
436
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437class AutoDrawLooper {
438public:
senorblanco87e066e2015-10-28 11:23:36 -0700439 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
440 // paint. It's used to determine the size of the offscreen layer for filters.
441 // If null, the clip will be used instead.
reed4a8126e2014-09-22 07:29:03 -0700442 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000443 bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700444 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000445 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700447 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000448 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700449 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000450 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000451
reeddbc3cef2015-04-29 12:18:57 -0700452 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
453 if (simplifiedCF) {
454 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
455 paint->setColorFilter(simplifiedCF)->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700456 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700457 fPaint = paint;
458 }
459
460 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700461 /**
462 * We implement ImageFilters for a given draw by creating a layer, then applying the
463 * imagefilter to the pixels of that layer (its backing surface/image), and then
464 * we call restore() to xfer that layer to the main canvas.
465 *
466 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
467 * 2. Generate the src pixels:
468 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
469 * return (fPaint). We then draw the primitive (using srcover) into a cleared
470 * buffer/surface.
471 * 3. Restore the layer created in #1
472 * The imagefilter is passed the buffer/surface from the layer (now filled with the
473 * src pixels of the primitive). It returns a new "filtered" buffer, which we
474 * draw onto the previous layer using the xfermode from the original paint.
475 */
reed@google.com8926b162012-03-23 15:36:36 +0000476 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700477 tmp.setImageFilter(fPaint->getImageFilter());
478 tmp.setXfermode(fPaint->getXfermode());
senorblanco87e066e2015-10-28 11:23:36 -0700479 SkRect storage;
480 if (rawBounds) {
481 // Make rawBounds include all paint outsets except for those due to image filters.
482 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
483 }
reed4960eee2015-12-18 07:09:18 -0800484 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp, 0),
reed76033be2015-03-14 10:54:31 -0700485 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700486 fTempLayerForImageFilter = true;
487 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000488 }
489
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000490 if (SkDrawLooper* looper = paint.getLooper()) {
491 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
492 looper->contextSize());
493 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000494 fIsSimple = false;
495 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700496 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000497 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700498 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000499 }
piotaixrb5fae932014-09-24 13:03:30 -0700500
reed4a8126e2014-09-22 07:29:03 -0700501 uint32_t oldFlags = paint.getFlags();
502 fNewPaintFlags = filter_paint_flags(props, oldFlags);
503 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700504 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700505 paint->setFlags(fNewPaintFlags);
506 fPaint = paint;
507 // if we're not simple, doNext() will take care of calling setFlags()
508 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000509 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000510
reed@android.com8a1c16f2008-12-17 15:59:43 +0000511 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700512 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000513 fCanvas->internalRestore();
514 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000515 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000517
reed@google.com4e2b3d32011-04-07 14:18:59 +0000518 const SkPaint& paint() const {
519 SkASSERT(fPaint);
520 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000522
reed@google.com129ec222012-05-15 13:24:09 +0000523 bool next(SkDrawFilter::Type drawType) {
524 if (fDone) {
525 return false;
526 } else if (fIsSimple) {
527 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000528 return !fPaint->nothingToDraw();
529 } else {
530 return this->doNext(drawType);
531 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000532 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000533
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534private:
reeddbc3cef2015-04-29 12:18:57 -0700535 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
536 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000537 SkCanvas* fCanvas;
538 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000539 SkDrawFilter* fFilter;
540 const SkPaint* fPaint;
541 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700542 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700543 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000544 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000545 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000546 SkDrawLooper::Context* fLooperContext;
547 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000548
549 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000550};
551
reed@google.com129ec222012-05-15 13:24:09 +0000552bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700553 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000554 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700555 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000556
reeddbc3cef2015-04-29 12:18:57 -0700557 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
558 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700559 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000560
reed5c476fb2015-04-20 08:04:21 -0700561 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700562 paint->setImageFilter(nullptr);
563 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000564 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000565
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000566 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000567 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000568 return false;
569 }
570 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000571 if (!fFilter->filter(paint, drawType)) {
572 fDone = true;
573 return false;
574 }
halcanary96fcdcc2015-08-27 07:41:13 -0700575 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000576 // no looper means we only draw once
577 fDone = true;
578 }
579 }
580 fPaint = paint;
581
582 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000583 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000584 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000585 }
586
587 // call this after any possible paint modifiers
588 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700589 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000590 return false;
591 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000592 return true;
593}
594
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595////////// macros to place around the internal draw calls //////////////////
596
reed262a71b2015-12-05 13:07:27 -0800597#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
598 this->predrawNotify(); \
599 AutoDrawLooper looper(this, fProps, paint, skipLayerForFilter, bounds); \
600 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
601 SkDrawIter iter(this);
602
603
reed@google.com8926b162012-03-23 15:36:36 +0000604#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000605 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700606 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000607 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000608 SkDrawIter iter(this);
609
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000610#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000611 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700612 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000613 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000615
reedc83a2972015-07-16 07:40:45 -0700616#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
617 this->predrawNotify(bounds, &paint, auxOpaque); \
618 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
619 while (looper.next(type)) { \
620 SkDrawIter iter(this);
621
reed@google.com4e2b3d32011-04-07 14:18:59 +0000622#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000623
624////////////////////////////////////////////////////////////////////////////
625
mtkleinfeaadee2015-04-08 11:25:48 -0700626void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
627 this->restoreToCount(1);
628 fCachedLocalClipBounds.setEmpty();
629 fCachedLocalClipBoundsDirty = true;
630 fClipStack->reset();
631 fMCRec->reset(bounds);
632
633 // We're peering through a lot of structs here. Only at this scope do we
634 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
635 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
636}
637
reedd9544982014-09-09 18:46:22 -0700638SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800639 if (device && device->forceConservativeRasterClip()) {
640 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
641 }
642 // Since init() is only called once by our constructors, it is safe to perform this
643 // const-cast.
644 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
645
reed@google.comc0784db2013-12-13 21:16:12 +0000646 fCachedLocalClipBounds.setEmpty();
647 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000648 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000649 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700650 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800651 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700652 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653
halcanary385fe4d2015-08-26 13:07:48 -0700654 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700655
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700657 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658
reeda499f902015-05-01 09:34:31 -0700659 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
660 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
halcanary96fcdcc2015-08-27 07:41:13 -0700661 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700662
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664
halcanary96fcdcc2015-08-27 07:41:13 -0700665 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000666
reedf92c8662014-08-18 08:02:43 -0700667 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700668 // The root device and the canvas should always have the same pixel geometry
669 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700670 device->onAttachToCanvas(this);
671 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800672 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700673 }
674 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000675}
676
reed@google.comcde92112011-07-06 20:00:52 +0000677SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000678 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700679 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800680 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000681{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000682 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000683
halcanary96fcdcc2015-08-27 07:41:13 -0700684 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000685}
686
reedd9544982014-09-09 18:46:22 -0700687static SkBitmap make_nopixels(int width, int height) {
688 SkBitmap bitmap;
689 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
690 return bitmap;
691}
692
693class SkNoPixelsBitmapDevice : public SkBitmapDevice {
694public:
robertphillipsfcf78292015-06-19 11:49:52 -0700695 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
696 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800697 {
698 this->setOrigin(bounds.x(), bounds.y());
699 }
reedd9544982014-09-09 18:46:22 -0700700
701private:
piotaixrb5fae932014-09-24 13:03:30 -0700702
reedd9544982014-09-09 18:46:22 -0700703 typedef SkBitmapDevice INHERITED;
704};
705
reed96a857e2015-01-25 10:33:58 -0800706SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000707 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800708 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800709 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000710{
711 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700712
halcanary385fe4d2015-08-26 13:07:48 -0700713 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
714 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700715}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000716
reed78e27682014-11-19 08:04:34 -0800717SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700718 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700719 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800720 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700721{
722 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700723
halcanary385fe4d2015-08-26 13:07:48 -0700724 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700725}
726
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000727SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000728 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700729 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800730 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000731{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700733
reedd9544982014-09-09 18:46:22 -0700734 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000735}
736
robertphillipsfcf78292015-06-19 11:49:52 -0700737SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
738 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700739 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800740 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700741{
742 inc_canvas();
743
744 this->init(device, flags);
745}
746
reed4a8126e2014-09-22 07:29:03 -0700747SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700748 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700749 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800750 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700751{
752 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700753
halcanary385fe4d2015-08-26 13:07:48 -0700754 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700755 this->init(device, kDefault_InitFlags);
756}
reed29c857d2014-09-21 10:25:07 -0700757
reed4a8126e2014-09-22 07:29:03 -0700758SkCanvas::SkCanvas(const SkBitmap& bitmap)
759 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
760 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800761 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700762{
763 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700764
halcanary385fe4d2015-08-26 13:07:48 -0700765 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700766 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000767}
768
769SkCanvas::~SkCanvas() {
770 // free up the contents of our deque
771 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000772
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773 this->internalRestore(); // restore the last, since we're going away
774
halcanary385fe4d2015-08-26 13:07:48 -0700775 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000776
reed@android.com8a1c16f2008-12-17 15:59:43 +0000777 dec_canvas();
778}
779
reed@android.com8a1c16f2008-12-17 15:59:43 +0000780SkDrawFilter* SkCanvas::getDrawFilter() const {
781 return fMCRec->fFilter;
782}
783
784SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700785 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000786 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
787 return filter;
788}
789
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000790SkMetaData& SkCanvas::getMetaData() {
791 // metadata users are rare, so we lazily allocate it. If that changes we
792 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700793 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000794 fMetaData = new SkMetaData;
795 }
796 return *fMetaData;
797}
798
reed@android.com8a1c16f2008-12-17 15:59:43 +0000799///////////////////////////////////////////////////////////////////////////////
800
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000801void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000802 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000803 if (device) {
804 device->flush();
805 }
806}
807
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000808SkISize SkCanvas::getTopLayerSize() const {
809 SkBaseDevice* d = this->getTopDevice();
810 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
811}
812
813SkIPoint SkCanvas::getTopLayerOrigin() const {
814 SkBaseDevice* d = this->getTopDevice();
815 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
816}
817
818SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000819 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000820 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
821}
822
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000823SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000825 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000826 SkASSERT(rec && rec->fLayer);
827 return rec->fLayer->fDevice;
828}
829
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000830SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000831 if (updateMatrixClip) {
832 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
833 }
reed@google.com9266fed2011-03-30 00:18:03 +0000834 return fMCRec->fTopLayer->fDevice;
835}
836
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000837bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
838 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
839 return false;
840 }
841
842 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700843 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700844 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000845 return false;
846 }
847 weAllocated = true;
848 }
849
reedcf01e312015-05-23 19:14:51 -0700850 SkAutoPixmapUnlock unlocker;
851 if (bitmap->requestLock(&unlocker)) {
852 const SkPixmap& pm = unlocker.pixmap();
853 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
854 return true;
855 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000856 }
857
858 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700859 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000860 }
861 return false;
862}
reed@google.com51df9e32010-12-23 19:29:18 +0000863
bsalomon@google.comc6980972011-11-02 19:57:21 +0000864bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000865 SkIRect r = srcRect;
866 const SkISize size = this->getBaseLayerSize();
867 if (!r.intersect(0, 0, size.width(), size.height())) {
868 bitmap->reset();
869 return false;
870 }
871
reed84825042014-09-02 12:50:45 -0700872 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000873 // bitmap will already be reset.
874 return false;
875 }
876 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
877 bitmap->reset();
878 return false;
879 }
880 return true;
881}
882
reed96472de2014-12-10 09:53:42 -0800883bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000884 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000885 if (!device) {
886 return false;
887 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000888 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800889
reed96472de2014-12-10 09:53:42 -0800890 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
891 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000892 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000893 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000894
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000895 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800896 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000897}
898
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000899bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
900 if (bitmap.getTexture()) {
901 return false;
902 }
reedcf01e312015-05-23 19:14:51 -0700903
904 SkAutoPixmapUnlock unlocker;
905 if (bitmap.requestLock(&unlocker)) {
906 const SkPixmap& pm = unlocker.pixmap();
907 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000908 }
909 return false;
910}
911
912bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
913 int x, int y) {
914 switch (origInfo.colorType()) {
915 case kUnknown_SkColorType:
916 case kIndex_8_SkColorType:
917 return false;
918 default:
919 break;
920 }
halcanary96fcdcc2015-08-27 07:41:13 -0700921 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000922 return false;
923 }
924
925 const SkISize size = this->getBaseLayerSize();
926 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
927 if (!target.intersect(0, 0, size.width(), size.height())) {
928 return false;
929 }
930
931 SkBaseDevice* device = this->getDevice();
932 if (!device) {
933 return false;
934 }
935
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000936 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700937 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000938
939 // if x or y are negative, then we have to adjust pixels
940 if (x > 0) {
941 x = 0;
942 }
943 if (y > 0) {
944 y = 0;
945 }
946 // here x,y are either 0 or negative
947 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
948
reed4af35f32014-06-27 17:47:49 -0700949 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700950 const bool completeOverwrite = info.dimensions() == size;
951 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700952
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000953 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000954 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000955}
reed@google.com51df9e32010-12-23 19:29:18 +0000956
junov@google.com4370aed2012-01-18 16:21:08 +0000957SkCanvas* SkCanvas::canvasForDrawIter() {
958 return this;
959}
960
reed@android.com8a1c16f2008-12-17 15:59:43 +0000961//////////////////////////////////////////////////////////////////////////////
962
reed@android.com8a1c16f2008-12-17 15:59:43 +0000963void SkCanvas::updateDeviceCMCache() {
964 if (fDeviceCMDirty) {
965 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700966 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000968
halcanary96fcdcc2015-08-27 07:41:13 -0700969 if (nullptr == layer->fNext) { // only one layer
970 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000972 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973 do {
reed687fa1c2015-04-07 08:00:56 -0700974 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700975 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976 }
977 fDeviceCMDirty = false;
978 }
979}
980
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981///////////////////////////////////////////////////////////////////////////////
982
reed2ff1fce2014-12-11 07:07:37 -0800983void SkCanvas::checkForDeferredSave() {
984 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800985 this->doSave();
986 }
987}
988
reedf0090cb2014-11-26 08:55:51 -0800989int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800990#ifdef SK_DEBUG
991 int count = 0;
992 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
993 for (;;) {
994 const MCRec* rec = (const MCRec*)iter.next();
995 if (!rec) {
996 break;
997 }
998 count += 1 + rec->fDeferredSaveCount;
999 }
1000 SkASSERT(count == fSaveCount);
1001#endif
1002 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001003}
1004
1005int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001006 fSaveCount += 1;
1007 fMCRec->fDeferredSaveCount += 1;
1008 return this->getSaveCount() - 1; // return our prev value
1009}
1010
1011void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001012 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001013
1014 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1015 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001016 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001017}
1018
1019void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001020 if (fMCRec->fDeferredSaveCount > 0) {
1021 SkASSERT(fSaveCount > 1);
1022 fSaveCount -= 1;
1023 fMCRec->fDeferredSaveCount -= 1;
1024 } else {
1025 // check for underflow
1026 if (fMCStack.count() > 1) {
1027 this->willRestore();
1028 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001029 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001030 this->internalRestore();
1031 this->didRestore();
1032 }
reedf0090cb2014-11-26 08:55:51 -08001033 }
1034}
1035
1036void SkCanvas::restoreToCount(int count) {
1037 // sanity check
1038 if (count < 1) {
1039 count = 1;
1040 }
mtkleinf0f14112014-12-12 08:46:25 -08001041
reedf0090cb2014-11-26 08:55:51 -08001042 int n = this->getSaveCount() - count;
1043 for (int i = 0; i < n; ++i) {
1044 this->restore();
1045 }
1046}
1047
reed2ff1fce2014-12-11 07:07:37 -08001048void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001049 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001050 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001051 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001052
reed687fa1c2015-04-07 08:00:56 -07001053 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054}
1055
reed4960eee2015-12-18 07:09:18 -08001056bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001057#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001058 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@google.comb93ba452014-03-10 19:47:58 +00001059#else
1060 return true;
1061#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062}
1063
reed4960eee2015-12-18 07:09:18 -08001064bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001065 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001066 SkIRect clipBounds;
1067 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001068 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001069 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001070
reed96e657d2015-03-10 17:30:07 -07001071 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1072
senorblanco87e066e2015-10-28 11:23:36 -07001073// This is a temporary hack, until individual filters can do their own
1074// bloating, when this will be removed.
1075#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
1076 SkRect storage;
1077#endif
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001078 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -07001079 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco87e066e2015-10-28 11:23:36 -07001080#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
1081 if (bounds && imageFilter->canComputeFastBounds()) {
1082 imageFilter->computeFastBounds(*bounds, &storage);
1083 bounds = &storage;
1084 } else {
1085 bounds = nullptr;
1086 }
senorblancodb64af32015-12-09 10:11:43 -08001087#else
1088 if (bounds && !imageFilter->canComputeFastBounds()) {
1089 bounds = nullptr;
1090 }
senorblanco87e066e2015-10-28 11:23:36 -07001091#endif
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001092 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001093 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001094 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001096
reed96e657d2015-03-10 17:30:07 -07001097 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098 r.roundOut(&ir);
1099 // early exit if the layer's bounds are clipped out
1100 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001101 if (BoundsAffectsClip(saveLayerFlags)) {
reed9b3aa542015-03-11 08:47:12 -07001102 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001103 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001104 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001105 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106 }
1107 } else { // no user bounds, so just use the clip
1108 ir = clipBounds;
1109 }
reed180aec42015-03-11 10:39:04 -07001110 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111
reed4960eee2015-12-18 07:09:18 -08001112 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001113 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -07001114 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -07001115 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001116 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001117 }
1118
1119 if (intersection) {
1120 *intersection = ir;
1121 }
1122 return true;
1123}
1124
reed4960eee2015-12-18 07:09:18 -08001125uint32_t SkCanvas::SaveFlagsToSaveLayerFlags(SaveFlags flags) {
1126 uint32_t layerFlags = 0;
1127
1128 if (0 == (flags & kClipToLayer_SaveFlag)) {
1129 layerFlags |= kDontClipToLayer_PrivateSaveLayerFlag;
reedd990e2f2014-12-22 11:58:30 -08001130 }
reed4960eee2015-12-18 07:09:18 -08001131 if (0 == (flags & kHasAlphaLayer_SaveFlag)) {
1132 layerFlags |= kIsOpaque_SaveLayerFlag;
1133 }
1134 return layerFlags;
1135}
1136
1137#ifdef SK_SUPPORT_LEGACY_SAVELAYERPARAMS
1138SkCanvas::SaveLayerStrategy SkCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
1139 uint32_t flags = 0;
1140
1141 if (0 == (rec.fSaveLayerFlags & kDontClipToLayer_PrivateSaveLayerFlag)) {
1142 flags |= kClipToLayer_SaveFlag;
1143 }
1144 if (0 == (rec.fSaveLayerFlags & kIsOpaque_SaveLayerFlag)) {
1145 flags |= kHasAlphaLayer_SaveFlag;
1146 }
1147 return this->willSaveLayer(rec.fBounds, rec.fPaint, (SaveFlags)flags);
1148}
1149#endif
1150
1151int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1152 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001153}
1154
reed2ff1fce2014-12-11 07:07:37 -08001155int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reed4960eee2015-12-18 07:09:18 -08001156 return this->saveLayer(SaveLayerRec(bounds, paint, SaveFlagsToSaveLayerFlags(flags)));
reed@google.com8926b162012-03-23 15:36:36 +00001157}
1158
reed70ee31b2015-12-10 13:44:45 -08001159int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001160 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1161}
1162
1163int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1164 SaveLayerRec rec(origRec);
1165 if (gIgnoreSaveLayerBounds) {
1166 rec.fBounds = nullptr;
1167 }
1168 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1169 fSaveCount += 1;
1170 this->internalSaveLayer(rec, strategy);
1171 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001172}
1173
robertphillips7354a4b2015-12-16 05:08:27 -08001174static void draw_filter_into_device(SkBaseDevice* src, SkImageFilter* filter, SkBaseDevice* dst) {
1175
1176 SkBitmap srcBM;
1177
1178#if SK_SUPPORT_GPU
1179 GrRenderTarget* srcRT = src->accessRenderTarget();
1180 if (srcRT && !srcRT->asTexture() && dst->accessRenderTarget()) {
1181 // When both the src & the dst are on the gpu but the src doesn't have a texture,
1182 // we create a temporary texture for the draw.
1183 // TODO: we should actually only copy the portion of the source needed to apply the image
1184 // filter
1185 GrContext* context = srcRT->getContext();
1186 SkAutoTUnref<GrTexture> tex(context->textureProvider()->createTexture(srcRT->desc(), true));
1187
1188 context->copySurface(tex, srcRT);
1189
1190 GrWrapTextureInBitmap(tex, src->width(), src->height(), src->isOpaque(), &srcBM);
1191 } else
1192#endif
1193 {
1194 srcBM = src->accessBitmap(false);
1195 }
1196
1197 SkCanvas c(dst);
1198
1199 SkPaint p;
1200 p.setImageFilter(filter);
1201 c.drawBitmap(srcBM, 0, 0, &p);
1202}
reed70ee31b2015-12-10 13:44:45 -08001203
reed4960eee2015-12-18 07:09:18 -08001204void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1205 const SkRect* bounds = rec.fBounds;
1206 const SkPaint* paint = rec.fPaint;
1207 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1208
reed@google.comb93ba452014-03-10 19:47:58 +00001209#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001210 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001211#endif
1212
junov@chromium.orga907ac32012-02-24 21:54:07 +00001213 // do this before we create the layer. We don't call the public save() since
1214 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001215 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001216
1217 fDeviceCMDirty = true;
1218
1219 SkIRect ir;
reed4960eee2015-12-18 07:09:18 -08001220 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, paint ? paint->getImageFilter() : nullptr)) {
reed2ff1fce2014-12-11 07:07:37 -08001221 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222 }
1223
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001224 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1225 // the clipRectBounds() call above?
1226 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001227 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001228 }
1229
reed4960eee2015-12-18 07:09:18 -08001230 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001231 SkPixelGeometry geo = fProps.pixelGeometry();
1232 if (paint) {
reed76033be2015-03-14 10:54:31 -07001233 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001234 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001235 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001236 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001237 }
1238 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001239 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1240 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241
reedb2db8982014-11-13 12:41:02 -08001242 SkBaseDevice* device = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001243 if (nullptr == device) {
reedb2db8982014-11-13 12:41:02 -08001244 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001245 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001246 }
reedb2db8982014-11-13 12:41:02 -08001247
reed61f501f2015-04-29 08:34:00 -07001248 bool forceSpriteOnRestore = false;
1249 {
reed70ee31b2015-12-10 13:44:45 -08001250 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001251 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001252 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001253 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1254 preserveLCDText, false);
reed61f501f2015-04-29 08:34:00 -07001255 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001256 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001257 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001258 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1259 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
halcanary96fcdcc2015-08-27 07:41:13 -07001260 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001261 SkErrorInternals::SetError(kInternalError_SkError,
1262 "Unable to create device for layer.");
1263 return;
1264 }
1265 forceSpriteOnRestore = true;
1266 }
1267 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001268 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001269
reed@google.com6f8f2922011-03-04 22:27:10 +00001270 device->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001271
1272 if (0) {
1273 draw_filter_into_device(fMCRec->fTopLayer->fDevice, nullptr, device);
1274 }
1275
halcanary385fe4d2015-08-26 13:07:48 -07001276 DeviceCM* layer =
1277 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278 device->unref();
1279
1280 layer->fNext = fMCRec->fTopLayer;
1281 fMCRec->fLayer = layer;
1282 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283}
1284
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001285int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1286 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1287}
1288
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1290 SaveFlags flags) {
1291 if (0xFF == alpha) {
halcanary96fcdcc2015-08-27 07:41:13 -07001292 return this->saveLayer(bounds, nullptr, flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293 } else {
1294 SkPaint tmpPaint;
1295 tmpPaint.setAlpha(alpha);
1296 return this->saveLayer(bounds, &tmpPaint, flags);
1297 }
1298}
1299
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300void SkCanvas::internalRestore() {
1301 SkASSERT(fMCStack.count() != 0);
1302
1303 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001304 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305
reed687fa1c2015-04-07 08:00:56 -07001306 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001307
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001308 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309 DeviceCM* layer = fMCRec->fLayer; // may be null
1310 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001311 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001312
1313 // now do the normal restore()
1314 fMCRec->~MCRec(); // balanced in save()
1315 fMCStack.pop_back();
1316 fMCRec = (MCRec*)fMCStack.back();
1317
1318 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1319 since if we're being recorded, we don't want to record this (the
1320 recorder will have already recorded the restore).
1321 */
bsalomon49f085d2014-09-05 13:34:00 -07001322 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001324 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001325 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001326 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001327 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001329 delete layer;
reedb679ca82015-04-07 04:40:48 -07001330 } else {
1331 // we're at the root
reeda499f902015-05-01 09:34:31 -07001332 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001333 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001335 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001336}
1337
reed4a8126e2014-09-22 07:29:03 -07001338SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001339 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001340 props = &fProps;
1341 }
1342 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001343}
1344
reed4a8126e2014-09-22 07:29:03 -07001345SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001346 SkBaseDevice* dev = this->getDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001347 return dev ? dev->newSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001348}
1349
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001350SkImageInfo SkCanvas::imageInfo() const {
1351 SkBaseDevice* dev = this->getDevice();
1352 if (dev) {
1353 return dev->imageInfo();
1354 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001355 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001356 }
1357}
1358
1359const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001360 SkPixmap pmap;
1361 if (!this->onPeekPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001362 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001363 }
1364 if (info) {
1365 *info = pmap.info();
1366 }
1367 if (rowBytes) {
1368 *rowBytes = pmap.rowBytes();
1369 }
1370 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001371}
1372
reed884e97c2015-05-26 11:31:54 -07001373bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001374 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001375 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001376}
1377
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001378void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001379 SkPixmap pmap;
1380 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001381 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001382 }
1383 if (info) {
1384 *info = pmap.info();
1385 }
1386 if (rowBytes) {
1387 *rowBytes = pmap.rowBytes();
1388 }
1389 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001390 *origin = this->getTopDevice(false)->getOrigin();
1391 }
reed884e97c2015-05-26 11:31:54 -07001392 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001393}
1394
reed884e97c2015-05-26 11:31:54 -07001395bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001396 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001397 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001398}
1399
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001400SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1401 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -07001402 if (nullptr == fAddr) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001403 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001404 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001405 return; // failure, fAddr is nullptr
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001406 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001407 if (!canvas->readPixels(&fBitmap, 0, 0)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001408 return; // failure, fAddr is nullptr
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001409 }
1410 fAddr = fBitmap.getPixels();
1411 fRowBytes = fBitmap.rowBytes();
1412 }
1413 SkASSERT(fAddr); // success
1414}
1415
1416bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1417 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001418 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001419 } else {
1420 bitmap->reset();
1421 return false;
1422 }
1423}
1424
reed@android.com8a1c16f2008-12-17 15:59:43 +00001425/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001426
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001427void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001428 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001430 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001431 paint = &tmp;
1432 }
reed@google.com4b226022011-01-11 18:32:13 +00001433
reed@google.com8926b162012-03-23 15:36:36 +00001434 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001435 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001436 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001437 paint = &looper.paint();
1438 SkImageFilter* filter = paint->getImageFilter();
1439 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001440 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001441 SkImageFilter::DeviceProxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001442 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001443 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001444 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001445 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001446 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblancodb64af32015-12-09 10:11:43 -08001447#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001448 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancodb64af32015-12-09 10:11:43 -08001449#else
1450 SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
1451#endif
senorblancobe129b22014-08-08 07:14:35 -07001452 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reedc9b5f8b2015-10-22 13:20:20 -07001453 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(),
1454 SkImageFilter::kApprox_SizeConstraint);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001455 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001456 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001457 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001458 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1459 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001460 }
reed61f501f2015-04-29 08:34:00 -07001461 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001462 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001463 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001464 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001465 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001466 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001467 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001468 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001469}
1470
reed32704672015-12-16 08:27:10 -08001471/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001472
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001473void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001474 SkMatrix m;
1475 m.setTranslate(dx, dy);
1476 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001477}
1478
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001479void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001480 SkMatrix m;
1481 m.setScale(sx, sy);
1482 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001483}
1484
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001485void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001486 SkMatrix m;
1487 m.setRotate(degrees);
1488 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001489}
1490
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001491void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001492 SkMatrix m;
1493 m.setSkew(sx, sy);
1494 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001495}
1496
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001497void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001498 if (matrix.isIdentity()) {
1499 return;
1500 }
1501
reed2ff1fce2014-12-11 07:07:37 -08001502 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001504 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001505 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001506
1507 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001508}
1509
reed86a17e72015-05-14 12:25:22 -07001510void SkCanvas::setMatrix(const SkMatrix& matrix) {
1511 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001512 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001513 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001514 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001515 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001516}
1517
reed@android.com8a1c16f2008-12-17 15:59:43 +00001518void SkCanvas::resetMatrix() {
1519 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001520
reed@android.com8a1c16f2008-12-17 15:59:43 +00001521 matrix.reset();
1522 this->setMatrix(matrix);
1523}
1524
1525//////////////////////////////////////////////////////////////////////////////
1526
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001527void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001528 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001529 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1530 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001531}
1532
1533void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001534#ifdef SK_ENABLE_CLIP_QUICKREJECT
1535 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001536 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001537 return false;
1538 }
1539
reed@google.com3b3e8952012-08-16 20:53:31 +00001540 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001541 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001542 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001543
reed687fa1c2015-04-07 08:00:56 -07001544 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001545 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001546 }
1547 }
1548#endif
1549
bsalomonac8cabd2015-11-20 18:53:07 -08001550 if (!fAllowSoftClip) {
1551 edgeStyle = kHard_ClipEdgeStyle;
1552 }
reed90ba0952015-11-20 13:42:47 -08001553
reedc64eff52015-11-21 12:39:45 -08001554 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1555 SkRect devR;
1556 if (rectStaysRect) {
1557 fMCRec->fMatrix.mapRect(&devR, rect);
1558 }
bsalomonac8cabd2015-11-20 18:53:07 -08001559
reedc64eff52015-11-21 12:39:45 -08001560 // Check if we can quick-accept the clip call (and do nothing)
1561 //
1562 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1563 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1564 // might allow lazy save/restores to eliminate entire save/restore blocks.
1565 //
1566 if (SkRegion::kIntersect_Op == op &&
1567 kHard_ClipEdgeStyle == edgeStyle
1568 && rectStaysRect)
1569 {
1570 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1571#if 0
1572 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1573 rect.left(), rect.top(), rect.right(), rect.bottom());
1574#endif
1575 return;
1576 }
1577 }
1578
1579 AutoValidateClip avc(this);
1580
1581 fDeviceCMDirty = true;
1582 fCachedLocalClipBoundsDirty = true;
1583
1584 if (rectStaysRect) {
1585 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1586 fClipStack->clipDevRect(devR, op, isAA);
1587 fMCRec->fRasterClip.op(devR, this->getBaseLayerSize(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001588 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001589 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001590 // and clip against that, since it can handle any matrix. However, to
1591 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1592 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001593 SkPath path;
1594
1595 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001596 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001597 }
1598}
1599
reed73e714e2014-09-04 09:02:23 -07001600static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1601 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001602 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001603}
1604
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001605void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001606 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001607 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001608 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001609 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1610 } else {
1611 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001612 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001613}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001614
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001615void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001616 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001617 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001618 AutoValidateClip avc(this);
1619
1620 fDeviceCMDirty = true;
1621 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001622 if (!fAllowSoftClip) {
1623 edgeStyle = kHard_ClipEdgeStyle;
1624 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001625
reed687fa1c2015-04-07 08:00:56 -07001626 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001627
robertphillips125f19a2015-11-23 09:00:05 -08001628 fMCRec->fRasterClip.op(transformedRRect, this->getBaseLayerSize(), op,
1629 kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001630 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001631 }
1632
1633 SkPath path;
1634 path.addRRect(rrect);
1635 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001636 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001637}
1638
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001639void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001640 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001641 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001642
1643 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1644 SkRect r;
1645 if (path.isRect(&r)) {
1646 this->onClipRect(r, op, edgeStyle);
1647 return;
1648 }
1649 SkRRect rrect;
1650 if (path.isOval(&r)) {
1651 rrect.setOval(r);
1652 this->onClipRRect(rrect, op, edgeStyle);
1653 return;
1654 }
1655 if (path.isRRect(&rrect)) {
1656 this->onClipRRect(rrect, op, edgeStyle);
1657 return;
1658 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001659 }
robertphillips39f05382015-11-24 09:30:12 -08001660
1661 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001662}
1663
1664void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001665#ifdef SK_ENABLE_CLIP_QUICKREJECT
1666 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001667 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001668 return false;
1669 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001670
reed@google.com3b3e8952012-08-16 20:53:31 +00001671 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001672 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001673 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001674
reed687fa1c2015-04-07 08:00:56 -07001675 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001676 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001677 }
1678 }
1679#endif
1680
reed@google.com5c3d1472011-02-22 19:12:23 +00001681 AutoValidateClip avc(this);
1682
reed@android.com8a1c16f2008-12-17 15:59:43 +00001683 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001684 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001685 if (!fAllowSoftClip) {
1686 edgeStyle = kHard_ClipEdgeStyle;
1687 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001688
1689 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001690 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001691
reed@google.comfe701122011-11-08 19:41:23 +00001692 // Check if the transfomation, or the original path itself
1693 // made us empty. Note this can also happen if we contained NaN
1694 // values. computing the bounds detects this, and will set our
1695 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1696 if (devPath.getBounds().isEmpty()) {
1697 // resetting the path will remove any NaN or other wanky values
1698 // that might upset our scan converter.
1699 devPath.reset();
1700 }
1701
reed@google.com5c3d1472011-02-22 19:12:23 +00001702 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001703 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001704
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001705 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001706 bool clipIsAA = getClipStack()->asPath(&devPath);
1707 if (clipIsAA) {
1708 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001709 }
fmalita1a481fe2015-02-04 07:39:34 -08001710
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001711 op = SkRegion::kReplace_Op;
1712 }
1713
reed73e714e2014-09-04 09:02:23 -07001714 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001715}
1716
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001717void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001718 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001719 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001720}
1721
1722void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001723 AutoValidateClip avc(this);
1724
reed@android.com8a1c16f2008-12-17 15:59:43 +00001725 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001726 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001727
reed@google.com5c3d1472011-02-22 19:12:23 +00001728 // todo: signal fClipStack that we have a region, and therefore (I guess)
1729 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001730 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001731
reed1f836ee2014-07-07 07:49:34 -07001732 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001733}
1734
reed@google.com819c9212011-02-23 18:56:55 +00001735#ifdef SK_DEBUG
1736void SkCanvas::validateClip() const {
1737 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001738 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001739 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001740 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001741 return;
1742 }
1743
reed@google.com819c9212011-02-23 18:56:55 +00001744 SkIRect ir;
1745 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001746 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001747
reed687fa1c2015-04-07 08:00:56 -07001748 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001749 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001750 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001751 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001752 case SkClipStack::Element::kRect_Type:
1753 element->getRect().round(&ir);
1754 tmpClip.op(ir, element->getOp());
1755 break;
1756 case SkClipStack::Element::kEmpty_Type:
1757 tmpClip.setEmpty();
1758 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001759 default: {
1760 SkPath path;
1761 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001762 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001763 break;
1764 }
reed@google.com819c9212011-02-23 18:56:55 +00001765 }
1766 }
reed@google.com819c9212011-02-23 18:56:55 +00001767}
1768#endif
1769
reed@google.com90c07ea2012-04-13 13:50:27 +00001770void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001771 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001772 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001773
halcanary96fcdcc2015-08-27 07:41:13 -07001774 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001775 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001776 }
1777}
1778
reed@google.com5c3d1472011-02-22 19:12:23 +00001779///////////////////////////////////////////////////////////////////////////////
1780
reed@google.com754de5f2014-02-24 19:38:20 +00001781bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001782 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001783}
1784
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001785bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001786 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001787}
1788
reed@google.com3b3e8952012-08-16 20:53:31 +00001789bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001790 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001791 return true;
1792
reed1f836ee2014-07-07 07:49:34 -07001793 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001794 return true;
1795 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001796
reed1f836ee2014-07-07 07:49:34 -07001797 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001798 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001799 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001800 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001801 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001802 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001803
reed@android.coma380ae42009-07-21 01:17:02 +00001804 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001805 // TODO: should we use | instead, or compare all 4 at once?
1806 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001807 return true;
1808 }
reed@google.comc0784db2013-12-13 21:16:12 +00001809 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001810 return true;
1811 }
1812 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001813 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001814}
1815
reed@google.com3b3e8952012-08-16 20:53:31 +00001816bool SkCanvas::quickReject(const SkPath& path) const {
1817 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001818}
1819
reed@google.com3b3e8952012-08-16 20:53:31 +00001820bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001821 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001822 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001823 return false;
1824 }
1825
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001826 SkMatrix inverse;
1827 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001828 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001829 if (bounds) {
1830 bounds->setEmpty();
1831 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001832 return false;
1833 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001834
bsalomon49f085d2014-09-05 13:34:00 -07001835 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001836 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001837 // adjust it outwards in case we are antialiasing
1838 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001839
reed@google.com8f4d2302013-12-17 16:44:46 +00001840 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1841 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001842 inverse.mapRect(bounds, r);
1843 }
1844 return true;
1845}
1846
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001847bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001848 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001849 if (clip.isEmpty()) {
1850 if (bounds) {
1851 bounds->setEmpty();
1852 }
1853 return false;
1854 }
1855
bsalomon49f085d2014-09-05 13:34:00 -07001856 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001857 *bounds = clip.getBounds();
1858 }
1859 return true;
1860}
1861
reed@android.com8a1c16f2008-12-17 15:59:43 +00001862const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001863 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001864}
1865
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001866const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001867 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001868}
1869
reed@google.com9c135db2014-03-12 18:28:35 +00001870GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1871 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001872 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001873}
1874
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001875GrContext* SkCanvas::getGrContext() {
1876#if SK_SUPPORT_GPU
1877 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001878 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001879 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001880 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001881 return renderTarget->getContext();
1882 }
1883 }
1884#endif
1885
halcanary96fcdcc2015-08-27 07:41:13 -07001886 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001887
1888}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001889
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001890void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1891 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001892 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001893 if (outer.isEmpty()) {
1894 return;
1895 }
1896 if (inner.isEmpty()) {
1897 this->drawRRect(outer, paint);
1898 return;
1899 }
1900
1901 // We don't have this method (yet), but technically this is what we should
1902 // be able to assert...
1903 // SkASSERT(outer.contains(inner));
1904 //
1905 // For now at least check for containment of bounds
1906 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1907
1908 this->onDrawDRRect(outer, inner, paint);
1909}
1910
reed41af9662015-01-05 07:49:08 -08001911// These need to stop being virtual -- clients need to override the onDraw... versions
1912
1913void SkCanvas::drawPaint(const SkPaint& paint) {
1914 this->onDrawPaint(paint);
1915}
1916
1917void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1918 this->onDrawRect(r, paint);
1919}
1920
1921void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1922 this->onDrawOval(r, paint);
1923}
1924
1925void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1926 this->onDrawRRect(rrect, paint);
1927}
1928
1929void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1930 this->onDrawPoints(mode, count, pts, paint);
1931}
1932
1933void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1934 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1935 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1936 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1937 indices, indexCount, paint);
1938}
1939
1940void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1941 this->onDrawPath(path, paint);
1942}
1943
reeda85d4d02015-05-06 12:56:48 -07001944void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1945 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001946}
1947
reede47829b2015-08-06 10:02:53 -07001948void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1949 const SkPaint* paint, SrcRectConstraint constraint) {
1950 if (dst.isEmpty() || src.isEmpty()) {
1951 return;
1952 }
1953 this->onDrawImageRect(image, &src, dst, paint, constraint);
1954}
reed41af9662015-01-05 07:49:08 -08001955
reed84984ef2015-07-17 07:09:43 -07001956void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1957 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001958 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001959}
1960
reede47829b2015-08-06 10:02:53 -07001961void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1962 SrcRectConstraint constraint) {
1963 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1964 constraint);
1965}
reede47829b2015-08-06 10:02:53 -07001966
reed4c21dc52015-06-25 12:32:03 -07001967void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1968 const SkPaint* paint) {
1969 if (dst.isEmpty()) {
1970 return;
1971 }
1972 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001973 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001974 }
1975 this->onDrawImageNine(image, center, dst, paint);
1976}
1977
reed41af9662015-01-05 07:49:08 -08001978void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001979 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001980 return;
1981 }
reed41af9662015-01-05 07:49:08 -08001982 this->onDrawBitmap(bitmap, dx, dy, paint);
1983}
1984
reede47829b2015-08-06 10:02:53 -07001985void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001986 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001987 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001988 return;
1989 }
reede47829b2015-08-06 10:02:53 -07001990 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001991}
1992
reed84984ef2015-07-17 07:09:43 -07001993void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1994 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001995 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001996}
1997
reede47829b2015-08-06 10:02:53 -07001998void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1999 SrcRectConstraint constraint) {
2000 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
2001 constraint);
2002}
reede47829b2015-08-06 10:02:53 -07002003
reed41af9662015-01-05 07:49:08 -08002004void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2005 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002006 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002007 return;
2008 }
reed4c21dc52015-06-25 12:32:03 -07002009 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07002010 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002011 }
reed41af9662015-01-05 07:49:08 -08002012 this->onDrawBitmapNine(bitmap, center, dst, paint);
2013}
2014
reed71c3c762015-06-24 10:29:17 -07002015void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2016 const SkColor colors[], int count, SkXfermode::Mode mode,
2017 const SkRect* cull, const SkPaint* paint) {
2018 if (count <= 0) {
2019 return;
2020 }
2021 SkASSERT(atlas);
2022 SkASSERT(xform);
2023 SkASSERT(tex);
2024 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2025}
2026
reede47829b2015-08-06 10:02:53 -07002027void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2028 const SkPaint* paint, SrcRectConstraint constraint) {
2029 if (src) {
2030 this->drawImageRect(image, *src, dst, paint, constraint);
2031 } else {
2032 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2033 dst, paint, constraint);
2034 }
2035}
2036void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2037 const SkPaint* paint, SrcRectConstraint constraint) {
2038 if (src) {
2039 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2040 } else {
2041 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2042 dst, paint, constraint);
2043 }
2044}
2045
reed@android.com8a1c16f2008-12-17 15:59:43 +00002046//////////////////////////////////////////////////////////////////////////////
2047// These are the virtual drawing methods
2048//////////////////////////////////////////////////////////////////////////////
2049
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002050void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002051 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002052 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2053 }
2054}
2055
reed41af9662015-01-05 07:49:08 -08002056void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002057 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002058 this->internalDrawPaint(paint);
2059}
2060
2061void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002062 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002063
2064 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002065 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002066 }
2067
reed@google.com4e2b3d32011-04-07 14:18:59 +00002068 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002069}
2070
reed41af9662015-01-05 07:49:08 -08002071void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2072 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002073 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002074 if ((long)count <= 0) {
2075 return;
2076 }
2077
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002078 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002079 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002080 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002081 // special-case 2 points (common for drawing a single line)
2082 if (2 == count) {
2083 r.set(pts[0], pts[1]);
2084 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002085 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002086 }
senorblanco87e066e2015-10-28 11:23:36 -07002087 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2088 return;
2089 }
2090 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002091 }
reed@google.coma584aed2012-05-16 14:06:02 +00002092
halcanary96fcdcc2015-08-27 07:41:13 -07002093 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002094
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002095 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002096
reed@android.com8a1c16f2008-12-17 15:59:43 +00002097 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002098 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002099 }
reed@google.com4b226022011-01-11 18:32:13 +00002100
reed@google.com4e2b3d32011-04-07 14:18:59 +00002101 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002102}
2103
reed41af9662015-01-05 07:49:08 -08002104void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002105 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002106 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002107 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002108 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002109 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2110 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2111 SkRect tmp(r);
2112 tmp.sort();
2113
senorblanco87e066e2015-10-28 11:23:36 -07002114 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2115 return;
2116 }
2117 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002118 }
reed@google.com4b226022011-01-11 18:32:13 +00002119
reedc83a2972015-07-16 07:40:45 -07002120 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002121
2122 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002123 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002124 }
2125
reed@google.com4e2b3d32011-04-07 14:18:59 +00002126 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002127}
2128
reed41af9662015-01-05 07:49:08 -08002129void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002130 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002131 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002132 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002133 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002134 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2135 return;
2136 }
2137 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002138 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002139
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002140 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002141
2142 while (iter.next()) {
2143 iter.fDevice->drawOval(iter, oval, looper.paint());
2144 }
2145
2146 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002147}
2148
reed41af9662015-01-05 07:49:08 -08002149void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002150 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002151 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002152 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002153 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002154 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2155 return;
2156 }
2157 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002158 }
2159
2160 if (rrect.isRect()) {
2161 // call the non-virtual version
2162 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002163 return;
2164 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002165 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002166 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2167 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002168 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002169
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002170 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002171
2172 while (iter.next()) {
2173 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2174 }
2175
2176 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002177}
2178
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002179void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2180 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002181 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002182 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002183 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002184 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2185 return;
2186 }
2187 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002188 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002189
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002190 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002191
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002192 while (iter.next()) {
2193 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2194 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002195
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002196 LOOPER_END
2197}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002198
reed41af9662015-01-05 07:49:08 -08002199void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002200 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002201 if (!path.isFinite()) {
2202 return;
2203 }
2204
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002205 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002206 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002207 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002208 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002209 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2210 return;
2211 }
2212 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002213 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002214
2215 const SkRect& r = path.getBounds();
2216 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002217 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002218 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002219 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002220 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002221 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002222
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002223 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002224
2225 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002226 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002227 }
2228
reed@google.com4e2b3d32011-04-07 14:18:59 +00002229 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002230}
2231
reed262a71b2015-12-05 13:07:27 -08002232bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
2233#ifdef SK_SUPPORT_LEGACY_LAYER_BITMAP_IMAGEFILTERS
2234 return false;
2235#endif
2236
2237 if (!paint.getImageFilter()) {
2238 return false;
2239 }
2240
2241 const SkMatrix& ctm = this->getTotalMatrix();
2242 const unsigned kSubpixelBits = 0; // matching SkDraw::drawBitmap()
2243 if (!SkTreatAsSprite(ctm, w, h, kSubpixelBits)) {
2244 return false;
2245 }
2246
2247 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2248 // Once we can filter and the filter will return a result larger than itself, we should be
2249 // able to remove this constraint.
2250 // skbug.com/4526
2251 //
2252 SkPoint pt;
2253 ctm.mapXY(x, y, &pt);
2254 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2255 return ir.contains(fMCRec->fRasterClip.getBounds());
2256}
2257
reeda85d4d02015-05-06 12:56:48 -07002258void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002259 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002260 SkRect bounds = SkRect::MakeXYWH(x, y,
2261 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002262 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002263 SkRect tmp = bounds;
2264 if (paint) {
2265 paint->computeFastBounds(tmp, &tmp);
2266 }
2267 if (this->quickReject(tmp)) {
2268 return;
2269 }
reeda85d4d02015-05-06 12:56:48 -07002270 }
2271
2272 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002273 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002274 paint = lazy.init();
2275 }
reed262a71b2015-12-05 13:07:27 -08002276
2277 const bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2278 *paint);
2279 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2280
reeda85d4d02015-05-06 12:56:48 -07002281 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002282 const SkPaint& pnt = looper.paint();
2283 if (drawAsSprite && pnt.getImageFilter()) {
2284 SkBitmap bitmap;
2285 if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2286 SkPoint pt;
2287 iter.fMatrix->mapXY(x, y, &pt);
2288 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2289 SkScalarRoundToInt(pt.fX),
2290 SkScalarRoundToInt(pt.fY), pnt);
2291 }
2292 } else {
2293 iter.fDevice->drawImage(iter, image, x, y, pnt);
2294 }
reeda85d4d02015-05-06 12:56:48 -07002295 }
2296
2297 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002298}
2299
reed41af9662015-01-05 07:49:08 -08002300void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002301 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002302 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002303 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002304 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002305 if (paint) {
2306 paint->computeFastBounds(dst, &storage);
2307 }
2308 if (this->quickReject(storage)) {
2309 return;
2310 }
reeda85d4d02015-05-06 12:56:48 -07002311 }
2312 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002313 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002314 paint = lazy.init();
2315 }
2316
senorblancoc41e7e12015-12-07 12:51:30 -08002317 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002318 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002319
2320 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002321 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002322 }
2323
2324 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002325}
2326
reed41af9662015-01-05 07:49:08 -08002327void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002328 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002329 SkDEBUGCODE(bitmap.validate();)
2330
reed33366972015-10-08 09:22:02 -07002331 if (bitmap.drawsNothing()) {
2332 return;
2333 }
2334
2335 SkLazyPaint lazy;
2336 if (nullptr == paint) {
2337 paint = lazy.init();
2338 }
2339
2340 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2341
2342 SkRect storage;
2343 const SkRect* bounds = nullptr;
2344 if (paint->canComputeFastBounds()) {
2345 bitmap.getBounds(&storage);
2346 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002347 SkRect tmp = storage;
2348 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2349 return;
2350 }
2351 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002352 }
reed@google.com4b226022011-01-11 18:32:13 +00002353
reed262a71b2015-12-05 13:07:27 -08002354 const bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2355 bitmap.height(), *paint);
2356 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002357
2358 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002359 const SkPaint& pnt = looper.paint();
2360 if (drawAsSprite && pnt.getImageFilter()) {
2361 SkPoint pt;
2362 iter.fMatrix->mapXY(x, y, &pt);
2363 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2364 SkScalarRoundToInt(pt.fX),
2365 SkScalarRoundToInt(pt.fY), pnt);
2366 } else {
2367 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2368 }
reed33366972015-10-08 09:22:02 -07002369 }
reed262a71b2015-12-05 13:07:27 -08002370
reed33366972015-10-08 09:22:02 -07002371 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002372}
2373
reed@google.com9987ec32011-09-07 11:57:52 +00002374// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002375void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002376 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002377 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002378 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002379 return;
2380 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002381
halcanary96fcdcc2015-08-27 07:41:13 -07002382 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002383 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002384 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2385 return;
2386 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002387 }
reed@google.com3d608122011-11-21 15:16:16 +00002388
reed@google.com33535f32012-09-25 15:37:50 +00002389 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002390 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002391 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002392 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002393
senorblancoc41e7e12015-12-07 12:51:30 -08002394 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002395 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002396
reed@google.com33535f32012-09-25 15:37:50 +00002397 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002398 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002399 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002400
reed@google.com33535f32012-09-25 15:37:50 +00002401 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002402}
2403
reed41af9662015-01-05 07:49:08 -08002404void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002405 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002406 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002407 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002408 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002409}
2410
reed4c21dc52015-06-25 12:32:03 -07002411void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2412 const SkPaint* paint) {
2413 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2414
halcanary96fcdcc2015-08-27 07:41:13 -07002415 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002416 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002417 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2418 return;
2419 }
reed@google.com3d608122011-11-21 15:16:16 +00002420 }
reed4c21dc52015-06-25 12:32:03 -07002421
2422 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002423 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002424 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002425 }
reed4c21dc52015-06-25 12:32:03 -07002426
senorblancoc41e7e12015-12-07 12:51:30 -08002427 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002428
2429 while (iter.next()) {
2430 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002431 }
reed4c21dc52015-06-25 12:32:03 -07002432
2433 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002434}
2435
reed41af9662015-01-05 07:49:08 -08002436void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2437 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002438 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002439 SkDEBUGCODE(bitmap.validate();)
2440
halcanary96fcdcc2015-08-27 07:41:13 -07002441 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002442 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002443 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2444 return;
2445 }
reed4c21dc52015-06-25 12:32:03 -07002446 }
2447
2448 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002449 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002450 paint = lazy.init();
2451 }
2452
senorblancoc41e7e12015-12-07 12:51:30 -08002453 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002454
2455 while (iter.next()) {
2456 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2457 }
2458
2459 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002460}
2461
reed@google.comf67e4cf2011-03-15 20:56:58 +00002462class SkDeviceFilteredPaint {
2463public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002464 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002465 uint32_t filteredFlags = device->filterTextFlags(paint);
2466 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002467 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002468 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002469 fPaint = newPaint;
2470 } else {
2471 fPaint = &paint;
2472 }
2473 }
2474
reed@google.comf67e4cf2011-03-15 20:56:58 +00002475 const SkPaint& paint() const { return *fPaint; }
2476
2477private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002478 const SkPaint* fPaint;
2479 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002480};
2481
bungeman@google.com52c748b2011-08-22 21:30:43 +00002482void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2483 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002484 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002485 draw.fDevice->drawRect(draw, r, paint);
2486 } else {
2487 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002488 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002489 draw.fDevice->drawRect(draw, r, p);
2490 }
2491}
2492
2493void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2494 const char text[], size_t byteLength,
2495 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002496 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002497
2498 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002499 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002500 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002501 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002502 return;
2503 }
2504
2505 SkScalar width = 0;
2506 SkPoint start;
2507
2508 start.set(0, 0); // to avoid warning
2509 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2510 SkPaint::kStrikeThruText_Flag)) {
2511 width = paint.measureText(text, byteLength);
2512
2513 SkScalar offsetX = 0;
2514 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2515 offsetX = SkScalarHalf(width);
2516 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2517 offsetX = width;
2518 }
2519 start.set(x - offsetX, y);
2520 }
2521
2522 if (0 == width) {
2523 return;
2524 }
2525
2526 uint32_t flags = paint.getFlags();
2527
2528 if (flags & (SkPaint::kUnderlineText_Flag |
2529 SkPaint::kStrikeThruText_Flag)) {
2530 SkScalar textSize = paint.getTextSize();
2531 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2532 SkRect r;
2533
2534 r.fLeft = start.fX;
2535 r.fRight = start.fX + width;
2536
2537 if (flags & SkPaint::kUnderlineText_Flag) {
2538 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2539 start.fY);
2540 r.fTop = offset;
2541 r.fBottom = offset + height;
2542 DrawRect(draw, paint, r, textSize);
2543 }
2544 if (flags & SkPaint::kStrikeThruText_Flag) {
2545 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2546 start.fY);
2547 r.fTop = offset;
2548 r.fBottom = offset + height;
2549 DrawRect(draw, paint, r, textSize);
2550 }
2551 }
2552}
2553
reed@google.come0d9ce82014-04-23 04:00:17 +00002554void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2555 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002556 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002557
2558 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002559 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002560 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002561 DrawTextDecorations(iter, dfp.paint(),
2562 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002563 }
2564
reed@google.com4e2b3d32011-04-07 14:18:59 +00002565 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002566}
2567
reed@google.come0d9ce82014-04-23 04:00:17 +00002568void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2569 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002570 SkPoint textOffset = SkPoint::Make(0, 0);
2571
halcanary96fcdcc2015-08-27 07:41:13 -07002572 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002573
reed@android.com8a1c16f2008-12-17 15:59:43 +00002574 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002575 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002576 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002577 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002578 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002579
reed@google.com4e2b3d32011-04-07 14:18:59 +00002580 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002581}
2582
reed@google.come0d9ce82014-04-23 04:00:17 +00002583void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2584 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002585
2586 SkPoint textOffset = SkPoint::Make(0, constY);
2587
halcanary96fcdcc2015-08-27 07:41:13 -07002588 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002589
reed@android.com8a1c16f2008-12-17 15:59:43 +00002590 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002591 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002592 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002593 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002594 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002595
reed@google.com4e2b3d32011-04-07 14:18:59 +00002596 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002597}
2598
reed@google.come0d9ce82014-04-23 04:00:17 +00002599void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2600 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002601 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002602
reed@android.com8a1c16f2008-12-17 15:59:43 +00002603 while (iter.next()) {
2604 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002605 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002606 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002607
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002608 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002609}
2610
fmalita00d5c2c2014-08-21 08:53:26 -07002611void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2612 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002613
fmalita85d5eb92015-03-04 11:20:12 -08002614 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002615 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002616 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002617 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002618 SkRect tmp;
2619 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2620 return;
2621 }
2622 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002623 }
2624
fmalita024f9962015-03-03 19:08:17 -08002625 // We cannot filter in the looper as we normally do, because the paint is
2626 // incomplete at this point (text-related attributes are embedded within blob run paints).
2627 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002628 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002629
fmalita85d5eb92015-03-04 11:20:12 -08002630 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002631
fmalitaaa1b9122014-08-28 14:32:24 -07002632 while (iter.next()) {
2633 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002634 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002635 }
2636
fmalitaaa1b9122014-08-28 14:32:24 -07002637 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002638
2639 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002640}
2641
reed@google.come0d9ce82014-04-23 04:00:17 +00002642// These will become non-virtual, so they always call the (virtual) onDraw... method
2643void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2644 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002645 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002646 this->onDrawText(text, byteLength, x, y, paint);
2647}
2648void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2649 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002650 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002651 this->onDrawPosText(text, byteLength, pos, paint);
2652}
2653void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2654 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002655 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002656 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2657}
2658void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2659 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002660 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002661 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2662}
fmalita00d5c2c2014-08-21 08:53:26 -07002663void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2664 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002665 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002666 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002667 this->onDrawTextBlob(blob, x, y, paint);
2668 }
2669}
reed@google.come0d9ce82014-04-23 04:00:17 +00002670
reed41af9662015-01-05 07:49:08 -08002671void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2672 const SkPoint verts[], const SkPoint texs[],
2673 const SkColor colors[], SkXfermode* xmode,
2674 const uint16_t indices[], int indexCount,
2675 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002676 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002677 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002678
reed@android.com8a1c16f2008-12-17 15:59:43 +00002679 while (iter.next()) {
2680 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002681 colors, xmode, indices, indexCount,
2682 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002683 }
reed@google.com4b226022011-01-11 18:32:13 +00002684
reed@google.com4e2b3d32011-04-07 14:18:59 +00002685 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002686}
2687
dandovb3c9d1c2014-08-12 08:34:29 -07002688void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2689 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002690 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002691 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002692 return;
2693 }
mtklein6cfa73a2014-08-13 13:33:49 -07002694
dandovecfff212014-08-04 10:02:00 -07002695 // Since a patch is always within the convex hull of the control points, we discard it when its
2696 // bounding rectangle is completely outside the current clip.
2697 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002698 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002699 if (this->quickReject(bounds)) {
2700 return;
2701 }
mtklein6cfa73a2014-08-13 13:33:49 -07002702
dandovb3c9d1c2014-08-12 08:34:29 -07002703 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2704}
2705
2706void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2707 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2708
halcanary96fcdcc2015-08-27 07:41:13 -07002709 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002710
dandovecfff212014-08-04 10:02:00 -07002711 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002712 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002713 }
mtklein6cfa73a2014-08-13 13:33:49 -07002714
dandovecfff212014-08-04 10:02:00 -07002715 LOOPER_END
2716}
2717
reeda8db7282015-07-07 10:22:31 -07002718void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2719 if (dr) {
2720 if (x || y) {
2721 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2722 this->onDrawDrawable(dr, &matrix);
2723 } else {
halcanary96fcdcc2015-08-27 07:41:13 -07002724 this->onDrawDrawable(dr, nullptr);
reeda8db7282015-07-07 10:22:31 -07002725 }
reed6a070dc2014-11-11 19:36:09 -08002726 }
2727}
2728
reeda8db7282015-07-07 10:22:31 -07002729void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2730 if (dr) {
2731 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002732 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002733 }
2734 this->onDrawDrawable(dr, matrix);
2735 }
2736}
2737
2738void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2739 SkRect bounds = dr->getBounds();
2740 if (matrix) {
2741 matrix->mapRect(&bounds);
2742 }
2743 if (this->quickReject(bounds)) {
2744 return;
2745 }
2746 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002747}
2748
reed71c3c762015-06-24 10:29:17 -07002749void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2750 const SkColor colors[], int count, SkXfermode::Mode mode,
2751 const SkRect* cull, const SkPaint* paint) {
2752 if (cull && this->quickReject(*cull)) {
2753 return;
2754 }
2755
2756 SkPaint pnt;
2757 if (paint) {
2758 pnt = *paint;
2759 }
2760
halcanary96fcdcc2015-08-27 07:41:13 -07002761 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002762 while (iter.next()) {
2763 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2764 }
2765 LOOPER_END
2766}
2767
reed@android.com8a1c16f2008-12-17 15:59:43 +00002768//////////////////////////////////////////////////////////////////////////////
2769// These methods are NOT virtual, and therefore must call back into virtual
2770// methods, rather than actually drawing themselves.
2771//////////////////////////////////////////////////////////////////////////////
2772
2773void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002774 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002775 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002776 SkPaint paint;
2777
2778 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002779 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002780 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 }
2782 this->drawPaint(paint);
2783}
2784
reed@android.com845fdac2009-06-23 03:01:32 +00002785void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002786 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002787 SkPaint paint;
2788
2789 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002790 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002791 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002792 }
2793 this->drawPaint(paint);
2794}
2795
2796void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002797 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002798 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002799
reed@android.com8a1c16f2008-12-17 15:59:43 +00002800 pt.set(x, y);
2801 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2802}
2803
2804void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002805 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002806 SkPoint pt;
2807 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002808
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809 pt.set(x, y);
2810 paint.setColor(color);
2811 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2812}
2813
2814void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2815 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002816 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002818
reed@android.com8a1c16f2008-12-17 15:59:43 +00002819 pts[0].set(x0, y0);
2820 pts[1].set(x1, y1);
2821 this->drawPoints(kLines_PointMode, 2, pts, paint);
2822}
2823
2824void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2825 SkScalar right, SkScalar bottom,
2826 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002827 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002828 SkRect r;
2829
2830 r.set(left, top, right, bottom);
2831 this->drawRect(r, paint);
2832}
2833
2834void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2835 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002836 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837 if (radius < 0) {
2838 radius = 0;
2839 }
2840
2841 SkRect r;
2842 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002843 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002844}
2845
2846void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2847 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002848 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002849 if (rx > 0 && ry > 0) {
2850 if (paint.canComputeFastBounds()) {
2851 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002852 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002853 return;
2854 }
2855 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002856 SkRRect rrect;
2857 rrect.setRectXY(r, rx, ry);
2858 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002859 } else {
2860 this->drawRect(r, paint);
2861 }
2862}
2863
reed@android.com8a1c16f2008-12-17 15:59:43 +00002864void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2865 SkScalar sweepAngle, bool useCenter,
2866 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002867 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002868 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2869 this->drawOval(oval, paint);
2870 } else {
2871 SkPath path;
2872 if (useCenter) {
2873 path.moveTo(oval.centerX(), oval.centerY());
2874 }
2875 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2876 if (useCenter) {
2877 path.close();
2878 }
2879 this->drawPath(path, paint);
2880 }
2881}
2882
2883void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2884 const SkPath& path, SkScalar hOffset,
2885 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002886 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002887 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002888
reed@android.com8a1c16f2008-12-17 15:59:43 +00002889 matrix.setTranslate(hOffset, vOffset);
2890 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2891}
2892
reed@android.comf76bacf2009-05-13 14:00:33 +00002893///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002894
2895/**
2896 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2897 * against the playback cost of recursing into the subpicture to get at its actual ops.
2898 *
2899 * For now we pick a conservatively small value, though measurement (and other heuristics like
2900 * the type of ops contained) may justify changing this value.
2901 */
2902#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002903
reedd5fa1a42014-08-09 11:08:05 -07002904void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002905 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002906 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002907 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002908 matrix = nullptr;
reedd5fa1a42014-08-09 11:08:05 -07002909 }
reed1c2c4412015-04-30 13:09:24 -07002910 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2911 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2912 picture->playback(this);
2913 } else {
2914 this->onDrawPicture(picture, matrix, paint);
2915 }
reedd5fa1a42014-08-09 11:08:05 -07002916 }
2917}
robertphillips9b14f262014-06-04 05:40:44 -07002918
reedd5fa1a42014-08-09 11:08:05 -07002919void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2920 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002921 if (!paint || paint->canComputeFastBounds()) {
2922 SkRect bounds = picture->cullRect();
2923 if (paint) {
2924 paint->computeFastBounds(bounds, &bounds);
2925 }
2926 if (matrix) {
2927 matrix->mapRect(&bounds);
2928 }
2929 if (this->quickReject(bounds)) {
2930 return;
2931 }
2932 }
2933
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002934 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002935 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002936 // Canvas has to first give the device the opportunity to render
2937 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002938 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002939 return; // the device has rendered the entire picture
2940 }
2941 }
2942
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002943 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002944 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002945}
2946
reed@android.com8a1c16f2008-12-17 15:59:43 +00002947///////////////////////////////////////////////////////////////////////////////
2948///////////////////////////////////////////////////////////////////////////////
2949
2950SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002951 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002952
2953 SkASSERT(canvas);
2954
2955 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2956 fDone = !fImpl->next();
2957}
2958
2959SkCanvas::LayerIter::~LayerIter() {
2960 fImpl->~SkDrawIter();
2961}
2962
2963void SkCanvas::LayerIter::next() {
2964 fDone = !fImpl->next();
2965}
2966
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002967SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002968 return fImpl->getDevice();
2969}
2970
2971const SkMatrix& SkCanvas::LayerIter::matrix() const {
2972 return fImpl->getMatrix();
2973}
2974
2975const SkPaint& SkCanvas::LayerIter::paint() const {
2976 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002977 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002978 paint = &fDefaultPaint;
2979 }
2980 return *paint;
2981}
2982
2983const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2984int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2985int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002986
2987///////////////////////////////////////////////////////////////////////////////
2988
fmalitac3b589a2014-06-05 12:40:07 -07002989SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002990
2991///////////////////////////////////////////////////////////////////////////////
2992
2993static bool supported_for_raster_canvas(const SkImageInfo& info) {
2994 switch (info.alphaType()) {
2995 case kPremul_SkAlphaType:
2996 case kOpaque_SkAlphaType:
2997 break;
2998 default:
2999 return false;
3000 }
3001
3002 switch (info.colorType()) {
3003 case kAlpha_8_SkColorType:
3004 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003005 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003006 break;
3007 default:
3008 return false;
3009 }
3010
3011 return true;
3012}
3013
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003014SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3015 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003016 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003017 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003018
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003019 SkBitmap bitmap;
3020 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003021 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003022 }
halcanary385fe4d2015-08-26 13:07:48 -07003023 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003024}
reedd5fa1a42014-08-09 11:08:05 -07003025
3026///////////////////////////////////////////////////////////////////////////////
3027
3028SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003029 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003030 : fCanvas(canvas)
3031 , fSaveCount(canvas->getSaveCount())
3032{
bsalomon49f085d2014-09-05 13:34:00 -07003033 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003034 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003035 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003036 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003037 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003038 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003039 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003040 canvas->save();
3041 }
mtklein6cfa73a2014-08-13 13:33:49 -07003042
bsalomon49f085d2014-09-05 13:34:00 -07003043 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003044 canvas->concat(*matrix);
3045 }
3046}
3047
3048SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3049 fCanvas->restoreToCount(fSaveCount);
3050}