blob: 68afc187a235b2aa02015bf54f9f3a5069169d2e [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
reedbada1882015-12-21 13:09:44 -08001125#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS
reed4960eee2015-12-18 07:09:18 -08001126uint32_t SkCanvas::SaveFlagsToSaveLayerFlags(SaveFlags flags) {
1127 uint32_t layerFlags = 0;
1128
1129 if (0 == (flags & kClipToLayer_SaveFlag)) {
1130 layerFlags |= kDontClipToLayer_PrivateSaveLayerFlag;
reedd990e2f2014-12-22 11:58:30 -08001131 }
reed4960eee2015-12-18 07:09:18 -08001132 if (0 == (flags & kHasAlphaLayer_SaveFlag)) {
1133 layerFlags |= kIsOpaque_SaveLayerFlag;
1134 }
1135 return layerFlags;
1136}
reedbada1882015-12-21 13:09:44 -08001137#endif
reed4960eee2015-12-18 07:09:18 -08001138
reed4960eee2015-12-18 07:09:18 -08001139int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1140 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001141}
1142
reedbada1882015-12-21 13:09:44 -08001143#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS
reed2ff1fce2014-12-11 07:07:37 -08001144int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reed4960eee2015-12-18 07:09:18 -08001145 return this->saveLayer(SaveLayerRec(bounds, paint, SaveFlagsToSaveLayerFlags(flags)));
reed@google.com8926b162012-03-23 15:36:36 +00001146}
reedbada1882015-12-21 13:09:44 -08001147#endif
reed@google.com8926b162012-03-23 15:36:36 +00001148
reed70ee31b2015-12-10 13:44:45 -08001149int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001150 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1151}
1152
1153int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1154 SaveLayerRec rec(origRec);
1155 if (gIgnoreSaveLayerBounds) {
1156 rec.fBounds = nullptr;
1157 }
1158 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1159 fSaveCount += 1;
1160 this->internalSaveLayer(rec, strategy);
1161 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001162}
1163
robertphillips7354a4b2015-12-16 05:08:27 -08001164static void draw_filter_into_device(SkBaseDevice* src, SkImageFilter* filter, SkBaseDevice* dst) {
1165
1166 SkBitmap srcBM;
1167
1168#if SK_SUPPORT_GPU
1169 GrRenderTarget* srcRT = src->accessRenderTarget();
1170 if (srcRT && !srcRT->asTexture() && dst->accessRenderTarget()) {
1171 // When both the src & the dst are on the gpu but the src doesn't have a texture,
1172 // we create a temporary texture for the draw.
1173 // TODO: we should actually only copy the portion of the source needed to apply the image
1174 // filter
1175 GrContext* context = srcRT->getContext();
1176 SkAutoTUnref<GrTexture> tex(context->textureProvider()->createTexture(srcRT->desc(), true));
1177
1178 context->copySurface(tex, srcRT);
1179
1180 GrWrapTextureInBitmap(tex, src->width(), src->height(), src->isOpaque(), &srcBM);
1181 } else
1182#endif
1183 {
1184 srcBM = src->accessBitmap(false);
1185 }
1186
1187 SkCanvas c(dst);
1188
1189 SkPaint p;
1190 p.setImageFilter(filter);
1191 c.drawBitmap(srcBM, 0, 0, &p);
1192}
reed70ee31b2015-12-10 13:44:45 -08001193
reed4960eee2015-12-18 07:09:18 -08001194void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1195 const SkRect* bounds = rec.fBounds;
1196 const SkPaint* paint = rec.fPaint;
1197 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1198
reed@google.comb93ba452014-03-10 19:47:58 +00001199#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001200 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001201#endif
1202
junov@chromium.orga907ac32012-02-24 21:54:07 +00001203 // do this before we create the layer. We don't call the public save() since
1204 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001205 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001206
1207 fDeviceCMDirty = true;
1208
1209 SkIRect ir;
reed4960eee2015-12-18 07:09:18 -08001210 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, paint ? paint->getImageFilter() : nullptr)) {
reed2ff1fce2014-12-11 07:07:37 -08001211 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212 }
1213
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001214 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1215 // the clipRectBounds() call above?
1216 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001217 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001218 }
1219
reed4960eee2015-12-18 07:09:18 -08001220 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001221 SkPixelGeometry geo = fProps.pixelGeometry();
1222 if (paint) {
reed76033be2015-03-14 10:54:31 -07001223 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001224 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001225 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001226 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001227 }
1228 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001229 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1230 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001231
reedb2db8982014-11-13 12:41:02 -08001232 SkBaseDevice* device = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001233 if (nullptr == device) {
reedb2db8982014-11-13 12:41:02 -08001234 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001235 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001236 }
reedb2db8982014-11-13 12:41:02 -08001237
reed61f501f2015-04-29 08:34:00 -07001238 bool forceSpriteOnRestore = false;
1239 {
reed70ee31b2015-12-10 13:44:45 -08001240 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001241 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001242 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001243 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1244 preserveLCDText, false);
reed61f501f2015-04-29 08:34:00 -07001245 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001246 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001247 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001248 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1249 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
halcanary96fcdcc2015-08-27 07:41:13 -07001250 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001251 SkErrorInternals::SetError(kInternalError_SkError,
1252 "Unable to create device for layer.");
1253 return;
1254 }
1255 forceSpriteOnRestore = true;
1256 }
1257 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001258 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001259
reed@google.com6f8f2922011-03-04 22:27:10 +00001260 device->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001261
1262 if (0) {
1263 draw_filter_into_device(fMCRec->fTopLayer->fDevice, nullptr, device);
1264 }
1265
halcanary385fe4d2015-08-26 13:07:48 -07001266 DeviceCM* layer =
1267 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001268 device->unref();
1269
1270 layer->fNext = fMCRec->fTopLayer;
1271 fMCRec->fLayer = layer;
1272 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273}
1274
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001275int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001276 if (0xFF == alpha) {
1277 return this->saveLayer(bounds, nullptr);
1278 } else {
1279 SkPaint tmpPaint;
1280 tmpPaint.setAlpha(alpha);
1281 return this->saveLayer(bounds, &tmpPaint);
1282 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001283}
1284
reedbada1882015-12-21 13:09:44 -08001285#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS
reed@android.com8a1c16f2008-12-17 15:59:43 +00001286int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1287 SaveFlags flags) {
1288 if (0xFF == alpha) {
halcanary96fcdcc2015-08-27 07:41:13 -07001289 return this->saveLayer(bounds, nullptr, flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290 } else {
1291 SkPaint tmpPaint;
1292 tmpPaint.setAlpha(alpha);
1293 return this->saveLayer(bounds, &tmpPaint, flags);
1294 }
1295}
reedbada1882015-12-21 13:09:44 -08001296#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298void SkCanvas::internalRestore() {
1299 SkASSERT(fMCStack.count() != 0);
1300
1301 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001302 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303
reed687fa1c2015-04-07 08:00:56 -07001304 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001305
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001306 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001307 DeviceCM* layer = fMCRec->fLayer; // may be null
1308 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001309 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310
1311 // now do the normal restore()
1312 fMCRec->~MCRec(); // balanced in save()
1313 fMCStack.pop_back();
1314 fMCRec = (MCRec*)fMCStack.back();
1315
1316 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1317 since if we're being recorded, we don't want to record this (the
1318 recorder will have already recorded the restore).
1319 */
bsalomon49f085d2014-09-05 13:34:00 -07001320 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001322 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001323 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001324 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001325 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001326 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001327 delete layer;
reedb679ca82015-04-07 04:40:48 -07001328 } else {
1329 // we're at the root
reeda499f902015-05-01 09:34:31 -07001330 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001331 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001333 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334}
1335
reed4a8126e2014-09-22 07:29:03 -07001336SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001337 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001338 props = &fProps;
1339 }
1340 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001341}
1342
reed4a8126e2014-09-22 07:29:03 -07001343SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001344 SkBaseDevice* dev = this->getDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001345 return dev ? dev->newSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001346}
1347
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001348SkImageInfo SkCanvas::imageInfo() const {
1349 SkBaseDevice* dev = this->getDevice();
1350 if (dev) {
1351 return dev->imageInfo();
1352 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001353 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001354 }
1355}
1356
1357const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001358 SkPixmap pmap;
1359 if (!this->onPeekPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001360 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001361 }
1362 if (info) {
1363 *info = pmap.info();
1364 }
1365 if (rowBytes) {
1366 *rowBytes = pmap.rowBytes();
1367 }
1368 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001369}
1370
reed884e97c2015-05-26 11:31:54 -07001371bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001372 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001373 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001374}
1375
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001376void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001377 SkPixmap pmap;
1378 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001379 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001380 }
1381 if (info) {
1382 *info = pmap.info();
1383 }
1384 if (rowBytes) {
1385 *rowBytes = pmap.rowBytes();
1386 }
1387 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001388 *origin = this->getTopDevice(false)->getOrigin();
1389 }
reed884e97c2015-05-26 11:31:54 -07001390 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001391}
1392
reed884e97c2015-05-26 11:31:54 -07001393bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001394 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001395 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001396}
1397
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001398SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1399 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -07001400 if (nullptr == fAddr) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001401 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001402 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001403 return; // failure, fAddr is nullptr
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001404 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001405 if (!canvas->readPixels(&fBitmap, 0, 0)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001406 return; // failure, fAddr is nullptr
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001407 }
1408 fAddr = fBitmap.getPixels();
1409 fRowBytes = fBitmap.rowBytes();
1410 }
1411 SkASSERT(fAddr); // success
1412}
1413
1414bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1415 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001416 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001417 } else {
1418 bitmap->reset();
1419 return false;
1420 }
1421}
1422
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001425void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001426 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001427 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001428 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001429 paint = &tmp;
1430 }
reed@google.com4b226022011-01-11 18:32:13 +00001431
reed@google.com8926b162012-03-23 15:36:36 +00001432 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001434 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001435 paint = &looper.paint();
1436 SkImageFilter* filter = paint->getImageFilter();
1437 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001438 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001439 SkImageFilter::DeviceProxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001440 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001441 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001442 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001443 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001444 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblancodb64af32015-12-09 10:11:43 -08001445#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001446 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancodb64af32015-12-09 10:11:43 -08001447#else
1448 SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
1449#endif
senorblancobe129b22014-08-08 07:14:35 -07001450 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reedc9b5f8b2015-10-22 13:20:20 -07001451 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(),
1452 SkImageFilter::kApprox_SizeConstraint);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001453 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001454 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001455 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001456 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1457 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001458 }
reed61f501f2015-04-29 08:34:00 -07001459 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001460 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001461 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001462 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001463 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001464 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001465 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001466 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001467}
1468
reed32704672015-12-16 08:27:10 -08001469/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001470
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001471void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001472 SkMatrix m;
1473 m.setTranslate(dx, dy);
1474 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001475}
1476
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001477void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001478 SkMatrix m;
1479 m.setScale(sx, sy);
1480 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001481}
1482
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001483void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001484 SkMatrix m;
1485 m.setRotate(degrees);
1486 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001487}
1488
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001489void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001490 SkMatrix m;
1491 m.setSkew(sx, sy);
1492 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001493}
1494
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001495void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001496 if (matrix.isIdentity()) {
1497 return;
1498 }
1499
reed2ff1fce2014-12-11 07:07:37 -08001500 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001502 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001503 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001504
1505 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001506}
1507
reed86a17e72015-05-14 12:25:22 -07001508void SkCanvas::setMatrix(const SkMatrix& matrix) {
1509 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001510 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001511 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001512 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001513 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001514}
1515
reed@android.com8a1c16f2008-12-17 15:59:43 +00001516void SkCanvas::resetMatrix() {
1517 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001518
reed@android.com8a1c16f2008-12-17 15:59:43 +00001519 matrix.reset();
1520 this->setMatrix(matrix);
1521}
1522
1523//////////////////////////////////////////////////////////////////////////////
1524
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001525void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001526 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001527 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1528 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001529}
1530
1531void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001532#ifdef SK_ENABLE_CLIP_QUICKREJECT
1533 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001534 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001535 return false;
1536 }
1537
reed@google.com3b3e8952012-08-16 20:53:31 +00001538 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001539 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001540 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001541
reed687fa1c2015-04-07 08:00:56 -07001542 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001543 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001544 }
1545 }
1546#endif
1547
bsalomonac8cabd2015-11-20 18:53:07 -08001548 if (!fAllowSoftClip) {
1549 edgeStyle = kHard_ClipEdgeStyle;
1550 }
reed90ba0952015-11-20 13:42:47 -08001551
reedc64eff52015-11-21 12:39:45 -08001552 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1553 SkRect devR;
1554 if (rectStaysRect) {
1555 fMCRec->fMatrix.mapRect(&devR, rect);
1556 }
bsalomonac8cabd2015-11-20 18:53:07 -08001557
reedc64eff52015-11-21 12:39:45 -08001558 // Check if we can quick-accept the clip call (and do nothing)
1559 //
1560 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1561 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1562 // might allow lazy save/restores to eliminate entire save/restore blocks.
1563 //
1564 if (SkRegion::kIntersect_Op == op &&
1565 kHard_ClipEdgeStyle == edgeStyle
1566 && rectStaysRect)
1567 {
1568 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1569#if 0
1570 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1571 rect.left(), rect.top(), rect.right(), rect.bottom());
1572#endif
1573 return;
1574 }
1575 }
1576
1577 AutoValidateClip avc(this);
1578
1579 fDeviceCMDirty = true;
1580 fCachedLocalClipBoundsDirty = true;
1581
1582 if (rectStaysRect) {
1583 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1584 fClipStack->clipDevRect(devR, op, isAA);
1585 fMCRec->fRasterClip.op(devR, this->getBaseLayerSize(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001586 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001587 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001588 // and clip against that, since it can handle any matrix. However, to
1589 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1590 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001591 SkPath path;
1592
1593 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001594 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001595 }
1596}
1597
reed73e714e2014-09-04 09:02:23 -07001598static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1599 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001600 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001601}
1602
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001603void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001604 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001605 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001606 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001607 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1608 } else {
1609 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001610 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001611}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001612
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001613void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001614 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001615 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001616 AutoValidateClip avc(this);
1617
1618 fDeviceCMDirty = true;
1619 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001620 if (!fAllowSoftClip) {
1621 edgeStyle = kHard_ClipEdgeStyle;
1622 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001623
reed687fa1c2015-04-07 08:00:56 -07001624 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001625
robertphillips125f19a2015-11-23 09:00:05 -08001626 fMCRec->fRasterClip.op(transformedRRect, this->getBaseLayerSize(), op,
1627 kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001628 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001629 }
1630
1631 SkPath path;
1632 path.addRRect(rrect);
1633 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001634 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001635}
1636
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001637void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001638 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001639 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001640
1641 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1642 SkRect r;
1643 if (path.isRect(&r)) {
1644 this->onClipRect(r, op, edgeStyle);
1645 return;
1646 }
1647 SkRRect rrect;
1648 if (path.isOval(&r)) {
1649 rrect.setOval(r);
1650 this->onClipRRect(rrect, op, edgeStyle);
1651 return;
1652 }
1653 if (path.isRRect(&rrect)) {
1654 this->onClipRRect(rrect, op, edgeStyle);
1655 return;
1656 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001657 }
robertphillips39f05382015-11-24 09:30:12 -08001658
1659 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001660}
1661
1662void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001663#ifdef SK_ENABLE_CLIP_QUICKREJECT
1664 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001665 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001666 return false;
1667 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001668
reed@google.com3b3e8952012-08-16 20:53:31 +00001669 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001670 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001671 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001672
reed687fa1c2015-04-07 08:00:56 -07001673 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001674 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001675 }
1676 }
1677#endif
1678
reed@google.com5c3d1472011-02-22 19:12:23 +00001679 AutoValidateClip avc(this);
1680
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001682 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001683 if (!fAllowSoftClip) {
1684 edgeStyle = kHard_ClipEdgeStyle;
1685 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001686
1687 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001688 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001689
reed@google.comfe701122011-11-08 19:41:23 +00001690 // Check if the transfomation, or the original path itself
1691 // made us empty. Note this can also happen if we contained NaN
1692 // values. computing the bounds detects this, and will set our
1693 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1694 if (devPath.getBounds().isEmpty()) {
1695 // resetting the path will remove any NaN or other wanky values
1696 // that might upset our scan converter.
1697 devPath.reset();
1698 }
1699
reed@google.com5c3d1472011-02-22 19:12:23 +00001700 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001701 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001702
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001703 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001704 bool clipIsAA = getClipStack()->asPath(&devPath);
1705 if (clipIsAA) {
1706 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001707 }
fmalita1a481fe2015-02-04 07:39:34 -08001708
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001709 op = SkRegion::kReplace_Op;
1710 }
1711
reed73e714e2014-09-04 09:02:23 -07001712 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001713}
1714
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001715void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001716 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001717 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001718}
1719
1720void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001721 AutoValidateClip avc(this);
1722
reed@android.com8a1c16f2008-12-17 15:59:43 +00001723 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001724 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001725
reed@google.com5c3d1472011-02-22 19:12:23 +00001726 // todo: signal fClipStack that we have a region, and therefore (I guess)
1727 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001728 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001729
reed1f836ee2014-07-07 07:49:34 -07001730 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001731}
1732
reed@google.com819c9212011-02-23 18:56:55 +00001733#ifdef SK_DEBUG
1734void SkCanvas::validateClip() const {
1735 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001736 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001737 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001738 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001739 return;
1740 }
1741
reed@google.com819c9212011-02-23 18:56:55 +00001742 SkIRect ir;
1743 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001744 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001745
reed687fa1c2015-04-07 08:00:56 -07001746 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001747 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001748 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001749 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001750 case SkClipStack::Element::kRect_Type:
1751 element->getRect().round(&ir);
1752 tmpClip.op(ir, element->getOp());
1753 break;
1754 case SkClipStack::Element::kEmpty_Type:
1755 tmpClip.setEmpty();
1756 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001757 default: {
1758 SkPath path;
1759 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001760 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001761 break;
1762 }
reed@google.com819c9212011-02-23 18:56:55 +00001763 }
1764 }
reed@google.com819c9212011-02-23 18:56:55 +00001765}
1766#endif
1767
reed@google.com90c07ea2012-04-13 13:50:27 +00001768void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001769 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001770 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001771
halcanary96fcdcc2015-08-27 07:41:13 -07001772 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001773 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001774 }
1775}
1776
reed@google.com5c3d1472011-02-22 19:12:23 +00001777///////////////////////////////////////////////////////////////////////////////
1778
reed@google.com754de5f2014-02-24 19:38:20 +00001779bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001780 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001781}
1782
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001783bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001784 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001785}
1786
reed@google.com3b3e8952012-08-16 20:53:31 +00001787bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001788 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001789 return true;
1790
reed1f836ee2014-07-07 07:49:34 -07001791 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001792 return true;
1793 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001794
reed1f836ee2014-07-07 07:49:34 -07001795 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001796 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001797 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001798 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001799 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001800 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001801
reed@android.coma380ae42009-07-21 01:17:02 +00001802 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001803 // TODO: should we use | instead, or compare all 4 at once?
1804 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001805 return true;
1806 }
reed@google.comc0784db2013-12-13 21:16:12 +00001807 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001808 return true;
1809 }
1810 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001811 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001812}
1813
reed@google.com3b3e8952012-08-16 20:53:31 +00001814bool SkCanvas::quickReject(const SkPath& path) const {
1815 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001816}
1817
reed@google.com3b3e8952012-08-16 20:53:31 +00001818bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001819 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001820 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001821 return false;
1822 }
1823
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001824 SkMatrix inverse;
1825 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001826 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001827 if (bounds) {
1828 bounds->setEmpty();
1829 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001830 return false;
1831 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001832
bsalomon49f085d2014-09-05 13:34:00 -07001833 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001834 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001835 // adjust it outwards in case we are antialiasing
1836 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001837
reed@google.com8f4d2302013-12-17 16:44:46 +00001838 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1839 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001840 inverse.mapRect(bounds, r);
1841 }
1842 return true;
1843}
1844
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001845bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001846 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001847 if (clip.isEmpty()) {
1848 if (bounds) {
1849 bounds->setEmpty();
1850 }
1851 return false;
1852 }
1853
bsalomon49f085d2014-09-05 13:34:00 -07001854 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001855 *bounds = clip.getBounds();
1856 }
1857 return true;
1858}
1859
reed@android.com8a1c16f2008-12-17 15:59:43 +00001860const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001861 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001862}
1863
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001864const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001865 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001866}
1867
reed@google.com9c135db2014-03-12 18:28:35 +00001868GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1869 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001870 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001871}
1872
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001873GrContext* SkCanvas::getGrContext() {
1874#if SK_SUPPORT_GPU
1875 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001876 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001877 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001878 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001879 return renderTarget->getContext();
1880 }
1881 }
1882#endif
1883
halcanary96fcdcc2015-08-27 07:41:13 -07001884 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001885
1886}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001887
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001888void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1889 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001890 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001891 if (outer.isEmpty()) {
1892 return;
1893 }
1894 if (inner.isEmpty()) {
1895 this->drawRRect(outer, paint);
1896 return;
1897 }
1898
1899 // We don't have this method (yet), but technically this is what we should
1900 // be able to assert...
1901 // SkASSERT(outer.contains(inner));
1902 //
1903 // For now at least check for containment of bounds
1904 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1905
1906 this->onDrawDRRect(outer, inner, paint);
1907}
1908
reed41af9662015-01-05 07:49:08 -08001909// These need to stop being virtual -- clients need to override the onDraw... versions
1910
1911void SkCanvas::drawPaint(const SkPaint& paint) {
1912 this->onDrawPaint(paint);
1913}
1914
1915void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1916 this->onDrawRect(r, paint);
1917}
1918
1919void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1920 this->onDrawOval(r, paint);
1921}
1922
1923void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1924 this->onDrawRRect(rrect, paint);
1925}
1926
1927void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1928 this->onDrawPoints(mode, count, pts, paint);
1929}
1930
1931void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1932 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1933 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1934 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1935 indices, indexCount, paint);
1936}
1937
1938void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1939 this->onDrawPath(path, paint);
1940}
1941
reeda85d4d02015-05-06 12:56:48 -07001942void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1943 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001944}
1945
reede47829b2015-08-06 10:02:53 -07001946void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1947 const SkPaint* paint, SrcRectConstraint constraint) {
1948 if (dst.isEmpty() || src.isEmpty()) {
1949 return;
1950 }
1951 this->onDrawImageRect(image, &src, dst, paint, constraint);
1952}
reed41af9662015-01-05 07:49:08 -08001953
reed84984ef2015-07-17 07:09:43 -07001954void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1955 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001956 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001957}
1958
reede47829b2015-08-06 10:02:53 -07001959void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1960 SrcRectConstraint constraint) {
1961 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1962 constraint);
1963}
reede47829b2015-08-06 10:02:53 -07001964
reed4c21dc52015-06-25 12:32:03 -07001965void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1966 const SkPaint* paint) {
1967 if (dst.isEmpty()) {
1968 return;
1969 }
1970 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001971 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001972 }
1973 this->onDrawImageNine(image, center, dst, paint);
1974}
1975
reed41af9662015-01-05 07:49:08 -08001976void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001977 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001978 return;
1979 }
reed41af9662015-01-05 07:49:08 -08001980 this->onDrawBitmap(bitmap, dx, dy, paint);
1981}
1982
reede47829b2015-08-06 10:02:53 -07001983void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001984 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001985 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001986 return;
1987 }
reede47829b2015-08-06 10:02:53 -07001988 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001989}
1990
reed84984ef2015-07-17 07:09:43 -07001991void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1992 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001993 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001994}
1995
reede47829b2015-08-06 10:02:53 -07001996void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1997 SrcRectConstraint constraint) {
1998 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1999 constraint);
2000}
reede47829b2015-08-06 10:02:53 -07002001
reed41af9662015-01-05 07:49:08 -08002002void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2003 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07002004 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07002005 return;
2006 }
reed4c21dc52015-06-25 12:32:03 -07002007 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07002008 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07002009 }
reed41af9662015-01-05 07:49:08 -08002010 this->onDrawBitmapNine(bitmap, center, dst, paint);
2011}
2012
reed71c3c762015-06-24 10:29:17 -07002013void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2014 const SkColor colors[], int count, SkXfermode::Mode mode,
2015 const SkRect* cull, const SkPaint* paint) {
2016 if (count <= 0) {
2017 return;
2018 }
2019 SkASSERT(atlas);
2020 SkASSERT(xform);
2021 SkASSERT(tex);
2022 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2023}
2024
reede47829b2015-08-06 10:02:53 -07002025void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2026 const SkPaint* paint, SrcRectConstraint constraint) {
2027 if (src) {
2028 this->drawImageRect(image, *src, dst, paint, constraint);
2029 } else {
2030 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2031 dst, paint, constraint);
2032 }
2033}
2034void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2035 const SkPaint* paint, SrcRectConstraint constraint) {
2036 if (src) {
2037 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2038 } else {
2039 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2040 dst, paint, constraint);
2041 }
2042}
2043
reed@android.com8a1c16f2008-12-17 15:59:43 +00002044//////////////////////////////////////////////////////////////////////////////
2045// These are the virtual drawing methods
2046//////////////////////////////////////////////////////////////////////////////
2047
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002048void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002049 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002050 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2051 }
2052}
2053
reed41af9662015-01-05 07:49:08 -08002054void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002055 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002056 this->internalDrawPaint(paint);
2057}
2058
2059void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002060 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002061
2062 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002063 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002064 }
2065
reed@google.com4e2b3d32011-04-07 14:18:59 +00002066 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002067}
2068
reed41af9662015-01-05 07:49:08 -08002069void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2070 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002071 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002072 if ((long)count <= 0) {
2073 return;
2074 }
2075
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002076 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002077 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002078 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002079 // special-case 2 points (common for drawing a single line)
2080 if (2 == count) {
2081 r.set(pts[0], pts[1]);
2082 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002083 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002084 }
senorblanco87e066e2015-10-28 11:23:36 -07002085 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2086 return;
2087 }
2088 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002089 }
reed@google.coma584aed2012-05-16 14:06:02 +00002090
halcanary96fcdcc2015-08-27 07:41:13 -07002091 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002092
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002093 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002094
reed@android.com8a1c16f2008-12-17 15:59:43 +00002095 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002096 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002097 }
reed@google.com4b226022011-01-11 18:32:13 +00002098
reed@google.com4e2b3d32011-04-07 14:18:59 +00002099 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002100}
2101
reed41af9662015-01-05 07:49:08 -08002102void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002103 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002104 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002105 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002106 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002107 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2108 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2109 SkRect tmp(r);
2110 tmp.sort();
2111
senorblanco87e066e2015-10-28 11:23:36 -07002112 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2113 return;
2114 }
2115 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002116 }
reed@google.com4b226022011-01-11 18:32:13 +00002117
reedc83a2972015-07-16 07:40:45 -07002118 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002119
2120 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002121 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002122 }
2123
reed@google.com4e2b3d32011-04-07 14:18:59 +00002124 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002125}
2126
reed41af9662015-01-05 07:49:08 -08002127void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002128 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002129 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002130 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002131 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002132 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2133 return;
2134 }
2135 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002136 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002137
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002138 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002139
2140 while (iter.next()) {
2141 iter.fDevice->drawOval(iter, oval, looper.paint());
2142 }
2143
2144 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002145}
2146
reed41af9662015-01-05 07:49:08 -08002147void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002148 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002149 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002150 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002151 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002152 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2153 return;
2154 }
2155 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002156 }
2157
2158 if (rrect.isRect()) {
2159 // call the non-virtual version
2160 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002161 return;
2162 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002163 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002164 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2165 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002166 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002167
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002168 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002169
2170 while (iter.next()) {
2171 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2172 }
2173
2174 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002175}
2176
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002177void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2178 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002179 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002180 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002181 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002182 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2183 return;
2184 }
2185 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002186 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002187
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002188 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002189
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002190 while (iter.next()) {
2191 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2192 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002193
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002194 LOOPER_END
2195}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002196
reed41af9662015-01-05 07:49:08 -08002197void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002198 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002199 if (!path.isFinite()) {
2200 return;
2201 }
2202
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002203 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002204 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002205 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002206 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002207 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2208 return;
2209 }
2210 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002211 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002212
2213 const SkRect& r = path.getBounds();
2214 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002215 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002216 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002217 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002218 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002219 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002220
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002221 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002222
2223 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002224 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002225 }
2226
reed@google.com4e2b3d32011-04-07 14:18:59 +00002227 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002228}
2229
reed262a71b2015-12-05 13:07:27 -08002230bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
2231#ifdef SK_SUPPORT_LEGACY_LAYER_BITMAP_IMAGEFILTERS
2232 return false;
2233#endif
2234
2235 if (!paint.getImageFilter()) {
2236 return false;
2237 }
2238
2239 const SkMatrix& ctm = this->getTotalMatrix();
2240 const unsigned kSubpixelBits = 0; // matching SkDraw::drawBitmap()
2241 if (!SkTreatAsSprite(ctm, w, h, kSubpixelBits)) {
2242 return false;
2243 }
2244
2245 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2246 // Once we can filter and the filter will return a result larger than itself, we should be
2247 // able to remove this constraint.
2248 // skbug.com/4526
2249 //
2250 SkPoint pt;
2251 ctm.mapXY(x, y, &pt);
2252 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2253 return ir.contains(fMCRec->fRasterClip.getBounds());
2254}
2255
reeda85d4d02015-05-06 12:56:48 -07002256void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002257 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002258 SkRect bounds = SkRect::MakeXYWH(x, y,
2259 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002260 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002261 SkRect tmp = bounds;
2262 if (paint) {
2263 paint->computeFastBounds(tmp, &tmp);
2264 }
2265 if (this->quickReject(tmp)) {
2266 return;
2267 }
reeda85d4d02015-05-06 12:56:48 -07002268 }
2269
2270 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002271 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002272 paint = lazy.init();
2273 }
reed262a71b2015-12-05 13:07:27 -08002274
2275 const bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2276 *paint);
2277 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2278
reeda85d4d02015-05-06 12:56:48 -07002279 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002280 const SkPaint& pnt = looper.paint();
2281 if (drawAsSprite && pnt.getImageFilter()) {
2282 SkBitmap bitmap;
2283 if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2284 SkPoint pt;
2285 iter.fMatrix->mapXY(x, y, &pt);
2286 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2287 SkScalarRoundToInt(pt.fX),
2288 SkScalarRoundToInt(pt.fY), pnt);
2289 }
2290 } else {
2291 iter.fDevice->drawImage(iter, image, x, y, pnt);
2292 }
reeda85d4d02015-05-06 12:56:48 -07002293 }
2294
2295 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002296}
2297
reed41af9662015-01-05 07:49:08 -08002298void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002299 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002300 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002301 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002302 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002303 if (paint) {
2304 paint->computeFastBounds(dst, &storage);
2305 }
2306 if (this->quickReject(storage)) {
2307 return;
2308 }
reeda85d4d02015-05-06 12:56:48 -07002309 }
2310 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002311 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002312 paint = lazy.init();
2313 }
2314
senorblancoc41e7e12015-12-07 12:51:30 -08002315 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002316 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002317
2318 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002319 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002320 }
2321
2322 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002323}
2324
reed41af9662015-01-05 07:49:08 -08002325void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002326 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002327 SkDEBUGCODE(bitmap.validate();)
2328
reed33366972015-10-08 09:22:02 -07002329 if (bitmap.drawsNothing()) {
2330 return;
2331 }
2332
2333 SkLazyPaint lazy;
2334 if (nullptr == paint) {
2335 paint = lazy.init();
2336 }
2337
2338 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2339
2340 SkRect storage;
2341 const SkRect* bounds = nullptr;
2342 if (paint->canComputeFastBounds()) {
2343 bitmap.getBounds(&storage);
2344 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002345 SkRect tmp = storage;
2346 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2347 return;
2348 }
2349 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002350 }
reed@google.com4b226022011-01-11 18:32:13 +00002351
reed262a71b2015-12-05 13:07:27 -08002352 const bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2353 bitmap.height(), *paint);
2354 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002355
2356 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002357 const SkPaint& pnt = looper.paint();
2358 if (drawAsSprite && pnt.getImageFilter()) {
2359 SkPoint pt;
2360 iter.fMatrix->mapXY(x, y, &pt);
2361 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2362 SkScalarRoundToInt(pt.fX),
2363 SkScalarRoundToInt(pt.fY), pnt);
2364 } else {
2365 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2366 }
reed33366972015-10-08 09:22:02 -07002367 }
reed262a71b2015-12-05 13:07:27 -08002368
reed33366972015-10-08 09:22:02 -07002369 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002370}
2371
reed@google.com9987ec32011-09-07 11:57:52 +00002372// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002373void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002374 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002375 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002376 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002377 return;
2378 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002379
halcanary96fcdcc2015-08-27 07:41:13 -07002380 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002381 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002382 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2383 return;
2384 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002385 }
reed@google.com3d608122011-11-21 15:16:16 +00002386
reed@google.com33535f32012-09-25 15:37:50 +00002387 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002388 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002389 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002390 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002391
senorblancoc41e7e12015-12-07 12:51:30 -08002392 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002393 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002394
reed@google.com33535f32012-09-25 15:37:50 +00002395 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002396 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002397 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002398
reed@google.com33535f32012-09-25 15:37:50 +00002399 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002400}
2401
reed41af9662015-01-05 07:49:08 -08002402void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002403 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002404 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002405 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002406 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002407}
2408
reed4c21dc52015-06-25 12:32:03 -07002409void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2410 const SkPaint* paint) {
2411 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2412
halcanary96fcdcc2015-08-27 07:41:13 -07002413 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002414 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002415 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2416 return;
2417 }
reed@google.com3d608122011-11-21 15:16:16 +00002418 }
reed4c21dc52015-06-25 12:32:03 -07002419
2420 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002421 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002422 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002423 }
reed4c21dc52015-06-25 12:32:03 -07002424
senorblancoc41e7e12015-12-07 12:51:30 -08002425 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002426
2427 while (iter.next()) {
2428 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002429 }
reed4c21dc52015-06-25 12:32:03 -07002430
2431 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002432}
2433
reed41af9662015-01-05 07:49:08 -08002434void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2435 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002436 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002437 SkDEBUGCODE(bitmap.validate();)
2438
halcanary96fcdcc2015-08-27 07:41:13 -07002439 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002440 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002441 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2442 return;
2443 }
reed4c21dc52015-06-25 12:32:03 -07002444 }
2445
2446 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002447 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002448 paint = lazy.init();
2449 }
2450
senorblancoc41e7e12015-12-07 12:51:30 -08002451 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002452
2453 while (iter.next()) {
2454 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2455 }
2456
2457 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002458}
2459
reed@google.comf67e4cf2011-03-15 20:56:58 +00002460class SkDeviceFilteredPaint {
2461public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002462 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002463 uint32_t filteredFlags = device->filterTextFlags(paint);
2464 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002465 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002466 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002467 fPaint = newPaint;
2468 } else {
2469 fPaint = &paint;
2470 }
2471 }
2472
reed@google.comf67e4cf2011-03-15 20:56:58 +00002473 const SkPaint& paint() const { return *fPaint; }
2474
2475private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002476 const SkPaint* fPaint;
2477 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002478};
2479
bungeman@google.com52c748b2011-08-22 21:30:43 +00002480void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2481 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002482 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002483 draw.fDevice->drawRect(draw, r, paint);
2484 } else {
2485 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002486 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002487 draw.fDevice->drawRect(draw, r, p);
2488 }
2489}
2490
2491void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2492 const char text[], size_t byteLength,
2493 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002494 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002495
2496 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002497 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002498 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002499 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002500 return;
2501 }
2502
2503 SkScalar width = 0;
2504 SkPoint start;
2505
2506 start.set(0, 0); // to avoid warning
2507 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2508 SkPaint::kStrikeThruText_Flag)) {
2509 width = paint.measureText(text, byteLength);
2510
2511 SkScalar offsetX = 0;
2512 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2513 offsetX = SkScalarHalf(width);
2514 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2515 offsetX = width;
2516 }
2517 start.set(x - offsetX, y);
2518 }
2519
2520 if (0 == width) {
2521 return;
2522 }
2523
2524 uint32_t flags = paint.getFlags();
2525
2526 if (flags & (SkPaint::kUnderlineText_Flag |
2527 SkPaint::kStrikeThruText_Flag)) {
2528 SkScalar textSize = paint.getTextSize();
2529 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2530 SkRect r;
2531
2532 r.fLeft = start.fX;
2533 r.fRight = start.fX + width;
2534
2535 if (flags & SkPaint::kUnderlineText_Flag) {
2536 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2537 start.fY);
2538 r.fTop = offset;
2539 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002540 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002541 }
2542 if (flags & SkPaint::kStrikeThruText_Flag) {
2543 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2544 start.fY);
2545 r.fTop = offset;
2546 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002547 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002548 }
2549 }
2550}
2551
reed@google.come0d9ce82014-04-23 04:00:17 +00002552void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2553 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002554 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002555
2556 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002557 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002558 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002559 DrawTextDecorations(iter, dfp.paint(),
2560 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002561 }
2562
reed@google.com4e2b3d32011-04-07 14:18:59 +00002563 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002564}
2565
reed@google.come0d9ce82014-04-23 04:00:17 +00002566void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2567 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002568 SkPoint textOffset = SkPoint::Make(0, 0);
2569
halcanary96fcdcc2015-08-27 07:41:13 -07002570 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002571
reed@android.com8a1c16f2008-12-17 15:59:43 +00002572 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002573 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002574 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002575 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002576 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002577
reed@google.com4e2b3d32011-04-07 14:18:59 +00002578 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002579}
2580
reed@google.come0d9ce82014-04-23 04:00:17 +00002581void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2582 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002583
2584 SkPoint textOffset = SkPoint::Make(0, constY);
2585
halcanary96fcdcc2015-08-27 07:41:13 -07002586 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002587
reed@android.com8a1c16f2008-12-17 15:59:43 +00002588 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002589 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002590 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002591 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002592 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002593
reed@google.com4e2b3d32011-04-07 14:18:59 +00002594 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002595}
2596
reed@google.come0d9ce82014-04-23 04:00:17 +00002597void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2598 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002599 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002600
reed@android.com8a1c16f2008-12-17 15:59:43 +00002601 while (iter.next()) {
2602 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002603 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002604 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002605
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002606 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002607}
2608
fmalita00d5c2c2014-08-21 08:53:26 -07002609void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2610 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002611
fmalita85d5eb92015-03-04 11:20:12 -08002612 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002613 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002614 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002615 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002616 SkRect tmp;
2617 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2618 return;
2619 }
2620 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002621 }
2622
fmalita024f9962015-03-03 19:08:17 -08002623 // We cannot filter in the looper as we normally do, because the paint is
2624 // incomplete at this point (text-related attributes are embedded within blob run paints).
2625 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002626 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002627
fmalita85d5eb92015-03-04 11:20:12 -08002628 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002629
fmalitaaa1b9122014-08-28 14:32:24 -07002630 while (iter.next()) {
2631 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002632 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002633 }
2634
fmalitaaa1b9122014-08-28 14:32:24 -07002635 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002636
2637 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002638}
2639
reed@google.come0d9ce82014-04-23 04:00:17 +00002640// These will become non-virtual, so they always call the (virtual) onDraw... method
2641void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2642 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002643 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002644 this->onDrawText(text, byteLength, x, y, paint);
2645}
2646void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2647 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002648 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002649 this->onDrawPosText(text, byteLength, pos, paint);
2650}
2651void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2652 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002653 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002654 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2655}
2656void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2657 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002658 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002659 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2660}
fmalita00d5c2c2014-08-21 08:53:26 -07002661void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2662 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002663 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002664 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002665 this->onDrawTextBlob(blob, x, y, paint);
2666 }
2667}
reed@google.come0d9ce82014-04-23 04:00:17 +00002668
reed41af9662015-01-05 07:49:08 -08002669void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2670 const SkPoint verts[], const SkPoint texs[],
2671 const SkColor colors[], SkXfermode* xmode,
2672 const uint16_t indices[], int indexCount,
2673 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002674 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002675 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002676
reed@android.com8a1c16f2008-12-17 15:59:43 +00002677 while (iter.next()) {
2678 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002679 colors, xmode, indices, indexCount,
2680 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002681 }
reed@google.com4b226022011-01-11 18:32:13 +00002682
reed@google.com4e2b3d32011-04-07 14:18:59 +00002683 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002684}
2685
dandovb3c9d1c2014-08-12 08:34:29 -07002686void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2687 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002688 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002689 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002690 return;
2691 }
mtklein6cfa73a2014-08-13 13:33:49 -07002692
dandovecfff212014-08-04 10:02:00 -07002693 // Since a patch is always within the convex hull of the control points, we discard it when its
2694 // bounding rectangle is completely outside the current clip.
2695 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002696 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002697 if (this->quickReject(bounds)) {
2698 return;
2699 }
mtklein6cfa73a2014-08-13 13:33:49 -07002700
dandovb3c9d1c2014-08-12 08:34:29 -07002701 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2702}
2703
2704void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2705 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2706
halcanary96fcdcc2015-08-27 07:41:13 -07002707 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002708
dandovecfff212014-08-04 10:02:00 -07002709 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002710 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002711 }
mtklein6cfa73a2014-08-13 13:33:49 -07002712
dandovecfff212014-08-04 10:02:00 -07002713 LOOPER_END
2714}
2715
reeda8db7282015-07-07 10:22:31 -07002716void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2717 if (dr) {
2718 if (x || y) {
2719 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2720 this->onDrawDrawable(dr, &matrix);
2721 } else {
halcanary96fcdcc2015-08-27 07:41:13 -07002722 this->onDrawDrawable(dr, nullptr);
reeda8db7282015-07-07 10:22:31 -07002723 }
reed6a070dc2014-11-11 19:36:09 -08002724 }
2725}
2726
reeda8db7282015-07-07 10:22:31 -07002727void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2728 if (dr) {
2729 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002730 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002731 }
2732 this->onDrawDrawable(dr, matrix);
2733 }
2734}
2735
2736void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2737 SkRect bounds = dr->getBounds();
2738 if (matrix) {
2739 matrix->mapRect(&bounds);
2740 }
2741 if (this->quickReject(bounds)) {
2742 return;
2743 }
2744 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002745}
2746
reed71c3c762015-06-24 10:29:17 -07002747void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2748 const SkColor colors[], int count, SkXfermode::Mode mode,
2749 const SkRect* cull, const SkPaint* paint) {
2750 if (cull && this->quickReject(*cull)) {
2751 return;
2752 }
2753
2754 SkPaint pnt;
2755 if (paint) {
2756 pnt = *paint;
2757 }
2758
halcanary96fcdcc2015-08-27 07:41:13 -07002759 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002760 while (iter.next()) {
2761 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2762 }
2763 LOOPER_END
2764}
2765
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766//////////////////////////////////////////////////////////////////////////////
2767// These methods are NOT virtual, and therefore must call back into virtual
2768// methods, rather than actually drawing themselves.
2769//////////////////////////////////////////////////////////////////////////////
2770
2771void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002772 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002773 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774 SkPaint paint;
2775
2776 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002777 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002778 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002779 }
2780 this->drawPaint(paint);
2781}
2782
reed@android.com845fdac2009-06-23 03:01:32 +00002783void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002784 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002785 SkPaint paint;
2786
2787 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002788 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002789 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790 }
2791 this->drawPaint(paint);
2792}
2793
2794void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002795 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002796 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002797
reed@android.com8a1c16f2008-12-17 15:59:43 +00002798 pt.set(x, y);
2799 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2800}
2801
2802void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002803 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002804 SkPoint pt;
2805 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002806
reed@android.com8a1c16f2008-12-17 15:59:43 +00002807 pt.set(x, y);
2808 paint.setColor(color);
2809 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2810}
2811
2812void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2813 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002814 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002815 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002816
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817 pts[0].set(x0, y0);
2818 pts[1].set(x1, y1);
2819 this->drawPoints(kLines_PointMode, 2, pts, paint);
2820}
2821
2822void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2823 SkScalar right, SkScalar bottom,
2824 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002825 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826 SkRect r;
2827
2828 r.set(left, top, right, bottom);
2829 this->drawRect(r, paint);
2830}
2831
2832void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2833 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002834 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002835 if (radius < 0) {
2836 radius = 0;
2837 }
2838
2839 SkRect r;
2840 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002841 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002842}
2843
2844void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2845 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002846 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002847 if (rx > 0 && ry > 0) {
2848 if (paint.canComputeFastBounds()) {
2849 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002850 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002851 return;
2852 }
2853 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002854 SkRRect rrect;
2855 rrect.setRectXY(r, rx, ry);
2856 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002857 } else {
2858 this->drawRect(r, paint);
2859 }
2860}
2861
reed@android.com8a1c16f2008-12-17 15:59:43 +00002862void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2863 SkScalar sweepAngle, bool useCenter,
2864 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002865 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002866 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2867 this->drawOval(oval, paint);
2868 } else {
2869 SkPath path;
2870 if (useCenter) {
2871 path.moveTo(oval.centerX(), oval.centerY());
2872 }
2873 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2874 if (useCenter) {
2875 path.close();
2876 }
2877 this->drawPath(path, paint);
2878 }
2879}
2880
2881void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2882 const SkPath& path, SkScalar hOffset,
2883 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002884 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002885 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002886
reed@android.com8a1c16f2008-12-17 15:59:43 +00002887 matrix.setTranslate(hOffset, vOffset);
2888 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2889}
2890
reed@android.comf76bacf2009-05-13 14:00:33 +00002891///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002892
2893/**
2894 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2895 * against the playback cost of recursing into the subpicture to get at its actual ops.
2896 *
2897 * For now we pick a conservatively small value, though measurement (and other heuristics like
2898 * the type of ops contained) may justify changing this value.
2899 */
2900#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002901
reedd5fa1a42014-08-09 11:08:05 -07002902void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002903 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002904 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002905 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002906 matrix = nullptr;
reedd5fa1a42014-08-09 11:08:05 -07002907 }
reed1c2c4412015-04-30 13:09:24 -07002908 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2909 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2910 picture->playback(this);
2911 } else {
2912 this->onDrawPicture(picture, matrix, paint);
2913 }
reedd5fa1a42014-08-09 11:08:05 -07002914 }
2915}
robertphillips9b14f262014-06-04 05:40:44 -07002916
reedd5fa1a42014-08-09 11:08:05 -07002917void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2918 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002919 if (!paint || paint->canComputeFastBounds()) {
2920 SkRect bounds = picture->cullRect();
2921 if (paint) {
2922 paint->computeFastBounds(bounds, &bounds);
2923 }
2924 if (matrix) {
2925 matrix->mapRect(&bounds);
2926 }
2927 if (this->quickReject(bounds)) {
2928 return;
2929 }
2930 }
2931
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002932 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002933 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002934 // Canvas has to first give the device the opportunity to render
2935 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002936 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002937 return; // the device has rendered the entire picture
2938 }
2939 }
2940
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002941 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002942 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002943}
2944
reed@android.com8a1c16f2008-12-17 15:59:43 +00002945///////////////////////////////////////////////////////////////////////////////
2946///////////////////////////////////////////////////////////////////////////////
2947
2948SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002949 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002950
2951 SkASSERT(canvas);
2952
2953 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2954 fDone = !fImpl->next();
2955}
2956
2957SkCanvas::LayerIter::~LayerIter() {
2958 fImpl->~SkDrawIter();
2959}
2960
2961void SkCanvas::LayerIter::next() {
2962 fDone = !fImpl->next();
2963}
2964
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002965SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002966 return fImpl->getDevice();
2967}
2968
2969const SkMatrix& SkCanvas::LayerIter::matrix() const {
2970 return fImpl->getMatrix();
2971}
2972
2973const SkPaint& SkCanvas::LayerIter::paint() const {
2974 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002975 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002976 paint = &fDefaultPaint;
2977 }
2978 return *paint;
2979}
2980
2981const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2982int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2983int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002984
2985///////////////////////////////////////////////////////////////////////////////
2986
fmalitac3b589a2014-06-05 12:40:07 -07002987SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002988
2989///////////////////////////////////////////////////////////////////////////////
2990
2991static bool supported_for_raster_canvas(const SkImageInfo& info) {
2992 switch (info.alphaType()) {
2993 case kPremul_SkAlphaType:
2994 case kOpaque_SkAlphaType:
2995 break;
2996 default:
2997 return false;
2998 }
2999
3000 switch (info.colorType()) {
3001 case kAlpha_8_SkColorType:
3002 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00003003 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00003004 break;
3005 default:
3006 return false;
3007 }
3008
3009 return true;
3010}
3011
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003012SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3013 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003014 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003015 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003016
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003017 SkBitmap bitmap;
3018 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003019 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003020 }
halcanary385fe4d2015-08-26 13:07:48 -07003021 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003022}
reedd5fa1a42014-08-09 11:08:05 -07003023
3024///////////////////////////////////////////////////////////////////////////////
3025
3026SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003027 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003028 : fCanvas(canvas)
3029 , fSaveCount(canvas->getSaveCount())
3030{
bsalomon49f085d2014-09-05 13:34:00 -07003031 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003032 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003033 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003034 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003035 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003036 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003037 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003038 canvas->save();
3039 }
mtklein6cfa73a2014-08-13 13:33:49 -07003040
bsalomon49f085d2014-09-05 13:34:00 -07003041 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003042 canvas->concat(*matrix);
3043 }
3044}
3045
3046SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3047 fCanvas->restoreToCount(fSaveCount);
3048}