blob: 414e94ed59acc76eb562d33a7a7e2791e7249b95 [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 }
senorblanco87e066e2015-10-28 11:23:36 -0700484 (void)canvas->internalSaveLayer(rawBounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001057#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
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
junov@chromium.orga907ac32012-02-24 21:54:07 +00001064bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
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)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001101 if (bounds_affects_clip(flags)) {
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
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +00001112 if (bounds_affects_clip(flags)) {
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
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001125int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -08001126 if (gIgnoreSaveLayerBounds) {
halcanary96fcdcc2015-08-27 07:41:13 -07001127 bounds = nullptr;
reedd990e2f2014-12-22 11:58:30 -08001128 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001129 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -07001130 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -07001131 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -08001132 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001133}
1134
reed2ff1fce2014-12-11 07:07:37 -08001135int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -08001136 if (gIgnoreSaveLayerBounds) {
halcanary96fcdcc2015-08-27 07:41:13 -07001137 bounds = nullptr;
reedd990e2f2014-12-22 11:58:30 -08001138 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001139 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -07001140 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -07001141 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -08001142 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +00001143}
1144
reed70ee31b2015-12-10 13:44:45 -08001145int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
1146 unsigned flags = kARGB_ClipLayer_SaveFlag | kPreserveLCDText_PrivateSaveFlag;
1147 return this->saveLayer(bounds, paint, (SaveFlags)flags);
1148}
1149
robertphillips7354a4b2015-12-16 05:08:27 -08001150static void draw_filter_into_device(SkBaseDevice* src, SkImageFilter* filter, SkBaseDevice* dst) {
1151
1152 SkBitmap srcBM;
1153
1154#if SK_SUPPORT_GPU
1155 GrRenderTarget* srcRT = src->accessRenderTarget();
1156 if (srcRT && !srcRT->asTexture() && dst->accessRenderTarget()) {
1157 // When both the src & the dst are on the gpu but the src doesn't have a texture,
1158 // we create a temporary texture for the draw.
1159 // TODO: we should actually only copy the portion of the source needed to apply the image
1160 // filter
1161 GrContext* context = srcRT->getContext();
1162 SkAutoTUnref<GrTexture> tex(context->textureProvider()->createTexture(srcRT->desc(), true));
1163
1164 context->copySurface(tex, srcRT);
1165
1166 GrWrapTextureInBitmap(tex, src->width(), src->height(), src->isOpaque(), &srcBM);
1167 } else
1168#endif
1169 {
1170 srcBM = src->accessBitmap(false);
1171 }
1172
1173 SkCanvas c(dst);
1174
1175 SkPaint p;
1176 p.setImageFilter(filter);
1177 c.drawBitmap(srcBM, 0, 0, &p);
1178}
reed70ee31b2015-12-10 13:44:45 -08001179
reed2ff1fce2014-12-11 07:07:37 -08001180void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -07001181 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +00001182#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +00001183 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001184#endif
1185
junov@chromium.orga907ac32012-02-24 21:54:07 +00001186 // do this before we create the layer. We don't call the public save() since
1187 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001188 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001189
1190 fDeviceCMDirty = true;
1191
1192 SkIRect ir;
halcanary96fcdcc2015-08-27 07:41:13 -07001193 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : nullptr)) {
reed2ff1fce2014-12-11 07:07:37 -08001194 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001195 }
1196
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001197 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1198 // the clipRectBounds() call above?
1199 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001200 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001201 }
1202
reed76033be2015-03-14 10:54:31 -07001203 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001204 SkPixelGeometry geo = fProps.pixelGeometry();
1205 if (paint) {
reed76033be2015-03-14 10:54:31 -07001206 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001207 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001208 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001209 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001210 }
1211 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001212 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1213 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001214
reedb2db8982014-11-13 12:41:02 -08001215 SkBaseDevice* device = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001216 if (nullptr == device) {
reedb2db8982014-11-13 12:41:02 -08001217 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001218 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001219 }
reedb2db8982014-11-13 12:41:02 -08001220
reed61f501f2015-04-29 08:34:00 -07001221 bool forceSpriteOnRestore = false;
1222 {
reed70ee31b2015-12-10 13:44:45 -08001223 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
1224 SkToBool(flags & kPreserveLCDText_PrivateSaveFlag);
reeddaa57bf2015-05-15 10:39:17 -07001225 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001226 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1227 preserveLCDText, false);
reed61f501f2015-04-29 08:34:00 -07001228 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001229 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001230 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001231 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1232 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
halcanary96fcdcc2015-08-27 07:41:13 -07001233 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001234 SkErrorInternals::SetError(kInternalError_SkError,
1235 "Unable to create device for layer.");
1236 return;
1237 }
1238 forceSpriteOnRestore = true;
1239 }
1240 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001241 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001242
reed@google.com6f8f2922011-03-04 22:27:10 +00001243 device->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001244
1245 if (0) {
1246 draw_filter_into_device(fMCRec->fTopLayer->fDevice, nullptr, device);
1247 }
1248
halcanary385fe4d2015-08-26 13:07:48 -07001249 DeviceCM* layer =
1250 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251 device->unref();
1252
1253 layer->fNext = fMCRec->fTopLayer;
1254 fMCRec->fLayer = layer;
1255 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001256}
1257
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001258int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1259 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1260}
1261
reed@android.com8a1c16f2008-12-17 15:59:43 +00001262int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1263 SaveFlags flags) {
1264 if (0xFF == alpha) {
halcanary96fcdcc2015-08-27 07:41:13 -07001265 return this->saveLayer(bounds, nullptr, flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266 } else {
1267 SkPaint tmpPaint;
1268 tmpPaint.setAlpha(alpha);
1269 return this->saveLayer(bounds, &tmpPaint, flags);
1270 }
1271}
1272
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273void SkCanvas::internalRestore() {
1274 SkASSERT(fMCStack.count() != 0);
1275
1276 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001277 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278
reed687fa1c2015-04-07 08:00:56 -07001279 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001280
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001281 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282 DeviceCM* layer = fMCRec->fLayer; // may be null
1283 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001284 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285
1286 // now do the normal restore()
1287 fMCRec->~MCRec(); // balanced in save()
1288 fMCStack.pop_back();
1289 fMCRec = (MCRec*)fMCStack.back();
1290
1291 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1292 since if we're being recorded, we don't want to record this (the
1293 recorder will have already recorded the restore).
1294 */
bsalomon49f085d2014-09-05 13:34:00 -07001295 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001297 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001298 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001299 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001300 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001302 delete layer;
reedb679ca82015-04-07 04:40:48 -07001303 } else {
1304 // we're at the root
reeda499f902015-05-01 09:34:31 -07001305 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001306 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001307 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001308 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309}
1310
reed4a8126e2014-09-22 07:29:03 -07001311SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001312 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001313 props = &fProps;
1314 }
1315 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001316}
1317
reed4a8126e2014-09-22 07:29:03 -07001318SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001319 SkBaseDevice* dev = this->getDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001320 return dev ? dev->newSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001321}
1322
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001323SkImageInfo SkCanvas::imageInfo() const {
1324 SkBaseDevice* dev = this->getDevice();
1325 if (dev) {
1326 return dev->imageInfo();
1327 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001328 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001329 }
1330}
1331
1332const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001333 SkPixmap pmap;
1334 if (!this->onPeekPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001335 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001336 }
1337 if (info) {
1338 *info = pmap.info();
1339 }
1340 if (rowBytes) {
1341 *rowBytes = pmap.rowBytes();
1342 }
1343 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001344}
1345
reed884e97c2015-05-26 11:31:54 -07001346bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001347 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001348 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001349}
1350
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001351void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001352 SkPixmap pmap;
1353 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001354 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001355 }
1356 if (info) {
1357 *info = pmap.info();
1358 }
1359 if (rowBytes) {
1360 *rowBytes = pmap.rowBytes();
1361 }
1362 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001363 *origin = this->getTopDevice(false)->getOrigin();
1364 }
reed884e97c2015-05-26 11:31:54 -07001365 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001366}
1367
reed884e97c2015-05-26 11:31:54 -07001368bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001369 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001370 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001371}
1372
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001373SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1374 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -07001375 if (nullptr == fAddr) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001376 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001377 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001378 return; // failure, fAddr is nullptr
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001379 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001380 if (!canvas->readPixels(&fBitmap, 0, 0)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001381 return; // failure, fAddr is nullptr
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001382 }
1383 fAddr = fBitmap.getPixels();
1384 fRowBytes = fBitmap.rowBytes();
1385 }
1386 SkASSERT(fAddr); // success
1387}
1388
1389bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1390 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001391 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001392 } else {
1393 bitmap->reset();
1394 return false;
1395 }
1396}
1397
reed@android.com8a1c16f2008-12-17 15:59:43 +00001398/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001399
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001400void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001401 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001402 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001403 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001404 paint = &tmp;
1405 }
reed@google.com4b226022011-01-11 18:32:13 +00001406
reed@google.com8926b162012-03-23 15:36:36 +00001407 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001408 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001409 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001410 paint = &looper.paint();
1411 SkImageFilter* filter = paint->getImageFilter();
1412 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001413 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001414 SkImageFilter::DeviceProxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001415 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001416 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001417 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001418 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001419 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblancodb64af32015-12-09 10:11:43 -08001420#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001421 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancodb64af32015-12-09 10:11:43 -08001422#else
1423 SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
1424#endif
senorblancobe129b22014-08-08 07:14:35 -07001425 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reedc9b5f8b2015-10-22 13:20:20 -07001426 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(),
1427 SkImageFilter::kApprox_SizeConstraint);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001428 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001429 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001430 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001431 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1432 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001433 }
reed61f501f2015-04-29 08:34:00 -07001434 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001435 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001436 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001437 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001438 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001439 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001440 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001441 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442}
1443
reed32704672015-12-16 08:27:10 -08001444/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001445
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001446void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001447 SkMatrix m;
1448 m.setTranslate(dx, dy);
1449 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450}
1451
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001452void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001453 SkMatrix m;
1454 m.setScale(sx, sy);
1455 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001456}
1457
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001458void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001459 SkMatrix m;
1460 m.setRotate(degrees);
1461 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001462}
1463
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001464void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001465 SkMatrix m;
1466 m.setSkew(sx, sy);
1467 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001468}
1469
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001470void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001471 if (matrix.isIdentity()) {
1472 return;
1473 }
1474
reed2ff1fce2014-12-11 07:07:37 -08001475 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001477 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001478 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001479
1480 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001481}
1482
reed86a17e72015-05-14 12:25:22 -07001483void SkCanvas::setMatrix(const SkMatrix& matrix) {
1484 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001485 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001486 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001487 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001488 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001489}
1490
reed@android.com8a1c16f2008-12-17 15:59:43 +00001491void SkCanvas::resetMatrix() {
1492 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001493
reed@android.com8a1c16f2008-12-17 15:59:43 +00001494 matrix.reset();
1495 this->setMatrix(matrix);
1496}
1497
1498//////////////////////////////////////////////////////////////////////////////
1499
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001500void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001501 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001502 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1503 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001504}
1505
1506void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001507#ifdef SK_ENABLE_CLIP_QUICKREJECT
1508 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001509 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001510 return false;
1511 }
1512
reed@google.com3b3e8952012-08-16 20:53:31 +00001513 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001514 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001515 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001516
reed687fa1c2015-04-07 08:00:56 -07001517 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001518 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001519 }
1520 }
1521#endif
1522
bsalomonac8cabd2015-11-20 18:53:07 -08001523 if (!fAllowSoftClip) {
1524 edgeStyle = kHard_ClipEdgeStyle;
1525 }
reed90ba0952015-11-20 13:42:47 -08001526
reedc64eff52015-11-21 12:39:45 -08001527 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1528 SkRect devR;
1529 if (rectStaysRect) {
1530 fMCRec->fMatrix.mapRect(&devR, rect);
1531 }
bsalomonac8cabd2015-11-20 18:53:07 -08001532
reedc64eff52015-11-21 12:39:45 -08001533 // Check if we can quick-accept the clip call (and do nothing)
1534 //
1535 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1536 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1537 // might allow lazy save/restores to eliminate entire save/restore blocks.
1538 //
1539 if (SkRegion::kIntersect_Op == op &&
1540 kHard_ClipEdgeStyle == edgeStyle
1541 && rectStaysRect)
1542 {
1543 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1544#if 0
1545 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1546 rect.left(), rect.top(), rect.right(), rect.bottom());
1547#endif
1548 return;
1549 }
1550 }
1551
1552 AutoValidateClip avc(this);
1553
1554 fDeviceCMDirty = true;
1555 fCachedLocalClipBoundsDirty = true;
1556
1557 if (rectStaysRect) {
1558 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1559 fClipStack->clipDevRect(devR, op, isAA);
1560 fMCRec->fRasterClip.op(devR, this->getBaseLayerSize(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001561 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001562 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001563 // and clip against that, since it can handle any matrix. However, to
1564 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1565 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001566 SkPath path;
1567
1568 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001569 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001570 }
1571}
1572
reed73e714e2014-09-04 09:02:23 -07001573static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1574 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001575 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001576}
1577
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001578void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001579 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001580 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001581 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001582 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1583 } else {
1584 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001585 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001586}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001587
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001588void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001589 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001590 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001591 AutoValidateClip avc(this);
1592
1593 fDeviceCMDirty = true;
1594 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001595 if (!fAllowSoftClip) {
1596 edgeStyle = kHard_ClipEdgeStyle;
1597 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001598
reed687fa1c2015-04-07 08:00:56 -07001599 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001600
robertphillips125f19a2015-11-23 09:00:05 -08001601 fMCRec->fRasterClip.op(transformedRRect, this->getBaseLayerSize(), op,
1602 kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001603 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001604 }
1605
1606 SkPath path;
1607 path.addRRect(rrect);
1608 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001609 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001610}
1611
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001612void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001613 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001614 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001615
1616 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1617 SkRect r;
1618 if (path.isRect(&r)) {
1619 this->onClipRect(r, op, edgeStyle);
1620 return;
1621 }
1622 SkRRect rrect;
1623 if (path.isOval(&r)) {
1624 rrect.setOval(r);
1625 this->onClipRRect(rrect, op, edgeStyle);
1626 return;
1627 }
1628 if (path.isRRect(&rrect)) {
1629 this->onClipRRect(rrect, op, edgeStyle);
1630 return;
1631 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001632 }
robertphillips39f05382015-11-24 09:30:12 -08001633
1634 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001635}
1636
1637void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001638#ifdef SK_ENABLE_CLIP_QUICKREJECT
1639 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001640 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001641 return false;
1642 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001643
reed@google.com3b3e8952012-08-16 20:53:31 +00001644 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001645 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001646 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001647
reed687fa1c2015-04-07 08:00:56 -07001648 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001649 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001650 }
1651 }
1652#endif
1653
reed@google.com5c3d1472011-02-22 19:12:23 +00001654 AutoValidateClip avc(this);
1655
reed@android.com8a1c16f2008-12-17 15:59:43 +00001656 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001657 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001658 if (!fAllowSoftClip) {
1659 edgeStyle = kHard_ClipEdgeStyle;
1660 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001661
1662 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001663 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664
reed@google.comfe701122011-11-08 19:41:23 +00001665 // Check if the transfomation, or the original path itself
1666 // made us empty. Note this can also happen if we contained NaN
1667 // values. computing the bounds detects this, and will set our
1668 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1669 if (devPath.getBounds().isEmpty()) {
1670 // resetting the path will remove any NaN or other wanky values
1671 // that might upset our scan converter.
1672 devPath.reset();
1673 }
1674
reed@google.com5c3d1472011-02-22 19:12:23 +00001675 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001676 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001677
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001678 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001679 bool clipIsAA = getClipStack()->asPath(&devPath);
1680 if (clipIsAA) {
1681 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001682 }
fmalita1a481fe2015-02-04 07:39:34 -08001683
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001684 op = SkRegion::kReplace_Op;
1685 }
1686
reed73e714e2014-09-04 09:02:23 -07001687 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001688}
1689
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001690void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001691 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001692 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001693}
1694
1695void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001696 AutoValidateClip avc(this);
1697
reed@android.com8a1c16f2008-12-17 15:59:43 +00001698 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001699 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001700
reed@google.com5c3d1472011-02-22 19:12:23 +00001701 // todo: signal fClipStack that we have a region, and therefore (I guess)
1702 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001703 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001704
reed1f836ee2014-07-07 07:49:34 -07001705 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001706}
1707
reed@google.com819c9212011-02-23 18:56:55 +00001708#ifdef SK_DEBUG
1709void SkCanvas::validateClip() const {
1710 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001711 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001712 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001713 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001714 return;
1715 }
1716
reed@google.com819c9212011-02-23 18:56:55 +00001717 SkIRect ir;
1718 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001719 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001720
reed687fa1c2015-04-07 08:00:56 -07001721 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001722 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001723 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001724 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001725 case SkClipStack::Element::kRect_Type:
1726 element->getRect().round(&ir);
1727 tmpClip.op(ir, element->getOp());
1728 break;
1729 case SkClipStack::Element::kEmpty_Type:
1730 tmpClip.setEmpty();
1731 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001732 default: {
1733 SkPath path;
1734 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001735 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001736 break;
1737 }
reed@google.com819c9212011-02-23 18:56:55 +00001738 }
1739 }
reed@google.com819c9212011-02-23 18:56:55 +00001740}
1741#endif
1742
reed@google.com90c07ea2012-04-13 13:50:27 +00001743void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001744 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001745 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001746
halcanary96fcdcc2015-08-27 07:41:13 -07001747 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001748 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001749 }
1750}
1751
reed@google.com5c3d1472011-02-22 19:12:23 +00001752///////////////////////////////////////////////////////////////////////////////
1753
reed@google.com754de5f2014-02-24 19:38:20 +00001754bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001755 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001756}
1757
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001758bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001759 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001760}
1761
reed@google.com3b3e8952012-08-16 20:53:31 +00001762bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001763 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001764 return true;
1765
reed1f836ee2014-07-07 07:49:34 -07001766 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001767 return true;
1768 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001769
reed1f836ee2014-07-07 07:49:34 -07001770 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001771 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001772 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001773 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001774 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001775 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001776
reed@android.coma380ae42009-07-21 01:17:02 +00001777 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001778 // TODO: should we use | instead, or compare all 4 at once?
1779 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001780 return true;
1781 }
reed@google.comc0784db2013-12-13 21:16:12 +00001782 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001783 return true;
1784 }
1785 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001786 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001787}
1788
reed@google.com3b3e8952012-08-16 20:53:31 +00001789bool SkCanvas::quickReject(const SkPath& path) const {
1790 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001791}
1792
reed@google.com3b3e8952012-08-16 20:53:31 +00001793bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001794 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001795 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001796 return false;
1797 }
1798
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001799 SkMatrix inverse;
1800 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001801 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001802 if (bounds) {
1803 bounds->setEmpty();
1804 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001805 return false;
1806 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001807
bsalomon49f085d2014-09-05 13:34:00 -07001808 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001809 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001810 // adjust it outwards in case we are antialiasing
1811 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001812
reed@google.com8f4d2302013-12-17 16:44:46 +00001813 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1814 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001815 inverse.mapRect(bounds, r);
1816 }
1817 return true;
1818}
1819
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001820bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001821 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001822 if (clip.isEmpty()) {
1823 if (bounds) {
1824 bounds->setEmpty();
1825 }
1826 return false;
1827 }
1828
bsalomon49f085d2014-09-05 13:34:00 -07001829 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001830 *bounds = clip.getBounds();
1831 }
1832 return true;
1833}
1834
reed@android.com8a1c16f2008-12-17 15:59:43 +00001835const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001836 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001837}
1838
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001839const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001840 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001841}
1842
reed@google.com9c135db2014-03-12 18:28:35 +00001843GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1844 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001845 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001846}
1847
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001848GrContext* SkCanvas::getGrContext() {
1849#if SK_SUPPORT_GPU
1850 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001851 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001852 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001853 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001854 return renderTarget->getContext();
1855 }
1856 }
1857#endif
1858
halcanary96fcdcc2015-08-27 07:41:13 -07001859 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001860
1861}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001862
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001863void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1864 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001865 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001866 if (outer.isEmpty()) {
1867 return;
1868 }
1869 if (inner.isEmpty()) {
1870 this->drawRRect(outer, paint);
1871 return;
1872 }
1873
1874 // We don't have this method (yet), but technically this is what we should
1875 // be able to assert...
1876 // SkASSERT(outer.contains(inner));
1877 //
1878 // For now at least check for containment of bounds
1879 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1880
1881 this->onDrawDRRect(outer, inner, paint);
1882}
1883
reed41af9662015-01-05 07:49:08 -08001884// These need to stop being virtual -- clients need to override the onDraw... versions
1885
1886void SkCanvas::drawPaint(const SkPaint& paint) {
1887 this->onDrawPaint(paint);
1888}
1889
1890void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1891 this->onDrawRect(r, paint);
1892}
1893
1894void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1895 this->onDrawOval(r, paint);
1896}
1897
1898void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1899 this->onDrawRRect(rrect, paint);
1900}
1901
1902void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1903 this->onDrawPoints(mode, count, pts, paint);
1904}
1905
1906void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1907 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1908 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1909 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1910 indices, indexCount, paint);
1911}
1912
1913void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1914 this->onDrawPath(path, paint);
1915}
1916
reeda85d4d02015-05-06 12:56:48 -07001917void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1918 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001919}
1920
reede47829b2015-08-06 10:02:53 -07001921void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1922 const SkPaint* paint, SrcRectConstraint constraint) {
1923 if (dst.isEmpty() || src.isEmpty()) {
1924 return;
1925 }
1926 this->onDrawImageRect(image, &src, dst, paint, constraint);
1927}
reed41af9662015-01-05 07:49:08 -08001928
reed84984ef2015-07-17 07:09:43 -07001929void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1930 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001931 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001932}
1933
reede47829b2015-08-06 10:02:53 -07001934void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1935 SrcRectConstraint constraint) {
1936 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1937 constraint);
1938}
reede47829b2015-08-06 10:02:53 -07001939
reed4c21dc52015-06-25 12:32:03 -07001940void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1941 const SkPaint* paint) {
1942 if (dst.isEmpty()) {
1943 return;
1944 }
1945 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001946 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001947 }
1948 this->onDrawImageNine(image, center, dst, paint);
1949}
1950
reed41af9662015-01-05 07:49:08 -08001951void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001952 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001953 return;
1954 }
reed41af9662015-01-05 07:49:08 -08001955 this->onDrawBitmap(bitmap, dx, dy, paint);
1956}
1957
reede47829b2015-08-06 10:02:53 -07001958void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001959 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001960 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001961 return;
1962 }
reede47829b2015-08-06 10:02:53 -07001963 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001964}
1965
reed84984ef2015-07-17 07:09:43 -07001966void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1967 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001968 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001969}
1970
reede47829b2015-08-06 10:02:53 -07001971void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1972 SrcRectConstraint constraint) {
1973 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1974 constraint);
1975}
reede47829b2015-08-06 10:02:53 -07001976
reed41af9662015-01-05 07:49:08 -08001977void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1978 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001979 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001980 return;
1981 }
reed4c21dc52015-06-25 12:32:03 -07001982 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001983 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001984 }
reed41af9662015-01-05 07:49:08 -08001985 this->onDrawBitmapNine(bitmap, center, dst, paint);
1986}
1987
reed71c3c762015-06-24 10:29:17 -07001988void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1989 const SkColor colors[], int count, SkXfermode::Mode mode,
1990 const SkRect* cull, const SkPaint* paint) {
1991 if (count <= 0) {
1992 return;
1993 }
1994 SkASSERT(atlas);
1995 SkASSERT(xform);
1996 SkASSERT(tex);
1997 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1998}
1999
reede47829b2015-08-06 10:02:53 -07002000void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2001 const SkPaint* paint, SrcRectConstraint constraint) {
2002 if (src) {
2003 this->drawImageRect(image, *src, dst, paint, constraint);
2004 } else {
2005 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2006 dst, paint, constraint);
2007 }
2008}
2009void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2010 const SkPaint* paint, SrcRectConstraint constraint) {
2011 if (src) {
2012 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2013 } else {
2014 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2015 dst, paint, constraint);
2016 }
2017}
2018
reed@android.com8a1c16f2008-12-17 15:59:43 +00002019//////////////////////////////////////////////////////////////////////////////
2020// These are the virtual drawing methods
2021//////////////////////////////////////////////////////////////////////////////
2022
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002023void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002024 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002025 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2026 }
2027}
2028
reed41af9662015-01-05 07:49:08 -08002029void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002030 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002031 this->internalDrawPaint(paint);
2032}
2033
2034void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002035 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002036
2037 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002038 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002039 }
2040
reed@google.com4e2b3d32011-04-07 14:18:59 +00002041 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002042}
2043
reed41af9662015-01-05 07:49:08 -08002044void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2045 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002046 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002047 if ((long)count <= 0) {
2048 return;
2049 }
2050
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002051 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002052 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002053 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002054 // special-case 2 points (common for drawing a single line)
2055 if (2 == count) {
2056 r.set(pts[0], pts[1]);
2057 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002058 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002059 }
senorblanco87e066e2015-10-28 11:23:36 -07002060 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2061 return;
2062 }
2063 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002064 }
reed@google.coma584aed2012-05-16 14:06:02 +00002065
halcanary96fcdcc2015-08-27 07:41:13 -07002066 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002067
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002068 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002069
reed@android.com8a1c16f2008-12-17 15:59:43 +00002070 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002071 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002072 }
reed@google.com4b226022011-01-11 18:32:13 +00002073
reed@google.com4e2b3d32011-04-07 14:18:59 +00002074 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002075}
2076
reed41af9662015-01-05 07:49:08 -08002077void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002078 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002079 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002080 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002081 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002082 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2083 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2084 SkRect tmp(r);
2085 tmp.sort();
2086
senorblanco87e066e2015-10-28 11:23:36 -07002087 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2088 return;
2089 }
2090 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002091 }
reed@google.com4b226022011-01-11 18:32:13 +00002092
reedc83a2972015-07-16 07:40:45 -07002093 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002094
2095 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002096 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002097 }
2098
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::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002103 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002104 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002105 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002106 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002107 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2108 return;
2109 }
2110 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002111 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002112
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002113 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002114
2115 while (iter.next()) {
2116 iter.fDevice->drawOval(iter, oval, looper.paint());
2117 }
2118
2119 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002120}
2121
reed41af9662015-01-05 07:49:08 -08002122void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002123 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002124 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002125 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002126 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002127 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2128 return;
2129 }
2130 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002131 }
2132
2133 if (rrect.isRect()) {
2134 // call the non-virtual version
2135 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002136 return;
2137 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002138 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002139 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2140 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002141 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002142
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002143 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002144
2145 while (iter.next()) {
2146 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2147 }
2148
2149 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002150}
2151
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002152void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2153 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002154 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002155 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002156 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002157 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2158 return;
2159 }
2160 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002161 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002162
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002163 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002164
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002165 while (iter.next()) {
2166 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2167 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002168
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002169 LOOPER_END
2170}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002171
reed41af9662015-01-05 07:49:08 -08002172void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002173 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002174 if (!path.isFinite()) {
2175 return;
2176 }
2177
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002178 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002179 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002180 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002181 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002182 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2183 return;
2184 }
2185 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002186 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002187
2188 const SkRect& r = path.getBounds();
2189 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002190 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002191 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002192 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002193 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002194 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002195
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002196 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002197
2198 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002199 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002200 }
2201
reed@google.com4e2b3d32011-04-07 14:18:59 +00002202 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002203}
2204
reed262a71b2015-12-05 13:07:27 -08002205bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
2206#ifdef SK_SUPPORT_LEGACY_LAYER_BITMAP_IMAGEFILTERS
2207 return false;
2208#endif
2209
2210 if (!paint.getImageFilter()) {
2211 return false;
2212 }
2213
2214 const SkMatrix& ctm = this->getTotalMatrix();
2215 const unsigned kSubpixelBits = 0; // matching SkDraw::drawBitmap()
2216 if (!SkTreatAsSprite(ctm, w, h, kSubpixelBits)) {
2217 return false;
2218 }
2219
2220 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2221 // Once we can filter and the filter will return a result larger than itself, we should be
2222 // able to remove this constraint.
2223 // skbug.com/4526
2224 //
2225 SkPoint pt;
2226 ctm.mapXY(x, y, &pt);
2227 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2228 return ir.contains(fMCRec->fRasterClip.getBounds());
2229}
2230
reeda85d4d02015-05-06 12:56:48 -07002231void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002232 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002233 SkRect bounds = SkRect::MakeXYWH(x, y,
2234 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002235 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002236 SkRect tmp = bounds;
2237 if (paint) {
2238 paint->computeFastBounds(tmp, &tmp);
2239 }
2240 if (this->quickReject(tmp)) {
2241 return;
2242 }
reeda85d4d02015-05-06 12:56:48 -07002243 }
2244
2245 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002246 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002247 paint = lazy.init();
2248 }
reed262a71b2015-12-05 13:07:27 -08002249
2250 const bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2251 *paint);
2252 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2253
reeda85d4d02015-05-06 12:56:48 -07002254 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002255 const SkPaint& pnt = looper.paint();
2256 if (drawAsSprite && pnt.getImageFilter()) {
2257 SkBitmap bitmap;
2258 if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2259 SkPoint pt;
2260 iter.fMatrix->mapXY(x, y, &pt);
2261 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2262 SkScalarRoundToInt(pt.fX),
2263 SkScalarRoundToInt(pt.fY), pnt);
2264 }
2265 } else {
2266 iter.fDevice->drawImage(iter, image, x, y, pnt);
2267 }
reeda85d4d02015-05-06 12:56:48 -07002268 }
2269
2270 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002271}
2272
reed41af9662015-01-05 07:49:08 -08002273void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002274 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002275 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002276 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002277 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002278 if (paint) {
2279 paint->computeFastBounds(dst, &storage);
2280 }
2281 if (this->quickReject(storage)) {
2282 return;
2283 }
reeda85d4d02015-05-06 12:56:48 -07002284 }
2285 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002286 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002287 paint = lazy.init();
2288 }
2289
senorblancoc41e7e12015-12-07 12:51:30 -08002290 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002291 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002292
2293 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002294 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002295 }
2296
2297 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002298}
2299
reed41af9662015-01-05 07:49:08 -08002300void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002301 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302 SkDEBUGCODE(bitmap.validate();)
2303
reed33366972015-10-08 09:22:02 -07002304 if (bitmap.drawsNothing()) {
2305 return;
2306 }
2307
2308 SkLazyPaint lazy;
2309 if (nullptr == paint) {
2310 paint = lazy.init();
2311 }
2312
2313 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2314
2315 SkRect storage;
2316 const SkRect* bounds = nullptr;
2317 if (paint->canComputeFastBounds()) {
2318 bitmap.getBounds(&storage);
2319 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002320 SkRect tmp = storage;
2321 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2322 return;
2323 }
2324 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002325 }
reed@google.com4b226022011-01-11 18:32:13 +00002326
reed262a71b2015-12-05 13:07:27 -08002327 const bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2328 bitmap.height(), *paint);
2329 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002330
2331 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002332 const SkPaint& pnt = looper.paint();
2333 if (drawAsSprite && pnt.getImageFilter()) {
2334 SkPoint pt;
2335 iter.fMatrix->mapXY(x, y, &pt);
2336 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2337 SkScalarRoundToInt(pt.fX),
2338 SkScalarRoundToInt(pt.fY), pnt);
2339 } else {
2340 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2341 }
reed33366972015-10-08 09:22:02 -07002342 }
reed262a71b2015-12-05 13:07:27 -08002343
reed33366972015-10-08 09:22:02 -07002344 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002345}
2346
reed@google.com9987ec32011-09-07 11:57:52 +00002347// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002348void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002349 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002350 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002351 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002352 return;
2353 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002354
halcanary96fcdcc2015-08-27 07:41:13 -07002355 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002356 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002357 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2358 return;
2359 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002360 }
reed@google.com3d608122011-11-21 15:16:16 +00002361
reed@google.com33535f32012-09-25 15:37:50 +00002362 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002363 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002364 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002365 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002366
senorblancoc41e7e12015-12-07 12:51:30 -08002367 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002368 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002369
reed@google.com33535f32012-09-25 15:37:50 +00002370 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002371 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002372 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002373
reed@google.com33535f32012-09-25 15:37:50 +00002374 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002375}
2376
reed41af9662015-01-05 07:49:08 -08002377void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002378 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002379 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002380 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002381 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002382}
2383
reed4c21dc52015-06-25 12:32:03 -07002384void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2385 const SkPaint* paint) {
2386 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2387
halcanary96fcdcc2015-08-27 07:41:13 -07002388 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002389 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002390 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2391 return;
2392 }
reed@google.com3d608122011-11-21 15:16:16 +00002393 }
reed4c21dc52015-06-25 12:32:03 -07002394
2395 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002396 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002397 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002398 }
reed4c21dc52015-06-25 12:32:03 -07002399
senorblancoc41e7e12015-12-07 12:51:30 -08002400 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002401
2402 while (iter.next()) {
2403 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002404 }
reed4c21dc52015-06-25 12:32:03 -07002405
2406 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002407}
2408
reed41af9662015-01-05 07:49:08 -08002409void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2410 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002411 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002412 SkDEBUGCODE(bitmap.validate();)
2413
halcanary96fcdcc2015-08-27 07:41:13 -07002414 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002415 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002416 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2417 return;
2418 }
reed4c21dc52015-06-25 12:32:03 -07002419 }
2420
2421 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002422 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002423 paint = lazy.init();
2424 }
2425
senorblancoc41e7e12015-12-07 12:51:30 -08002426 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002427
2428 while (iter.next()) {
2429 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2430 }
2431
2432 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002433}
2434
reed@google.comf67e4cf2011-03-15 20:56:58 +00002435class SkDeviceFilteredPaint {
2436public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002437 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002438 uint32_t filteredFlags = device->filterTextFlags(paint);
2439 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002440 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002441 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002442 fPaint = newPaint;
2443 } else {
2444 fPaint = &paint;
2445 }
2446 }
2447
reed@google.comf67e4cf2011-03-15 20:56:58 +00002448 const SkPaint& paint() const { return *fPaint; }
2449
2450private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002451 const SkPaint* fPaint;
2452 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002453};
2454
bungeman@google.com52c748b2011-08-22 21:30:43 +00002455void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2456 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002457 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002458 draw.fDevice->drawRect(draw, r, paint);
2459 } else {
2460 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002461 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002462 draw.fDevice->drawRect(draw, r, p);
2463 }
2464}
2465
2466void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2467 const char text[], size_t byteLength,
2468 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002469 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002470
2471 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002472 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002473 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002474 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002475 return;
2476 }
2477
2478 SkScalar width = 0;
2479 SkPoint start;
2480
2481 start.set(0, 0); // to avoid warning
2482 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2483 SkPaint::kStrikeThruText_Flag)) {
2484 width = paint.measureText(text, byteLength);
2485
2486 SkScalar offsetX = 0;
2487 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2488 offsetX = SkScalarHalf(width);
2489 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2490 offsetX = width;
2491 }
2492 start.set(x - offsetX, y);
2493 }
2494
2495 if (0 == width) {
2496 return;
2497 }
2498
2499 uint32_t flags = paint.getFlags();
2500
2501 if (flags & (SkPaint::kUnderlineText_Flag |
2502 SkPaint::kStrikeThruText_Flag)) {
2503 SkScalar textSize = paint.getTextSize();
2504 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2505 SkRect r;
2506
2507 r.fLeft = start.fX;
2508 r.fRight = start.fX + width;
2509
2510 if (flags & SkPaint::kUnderlineText_Flag) {
2511 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2512 start.fY);
2513 r.fTop = offset;
2514 r.fBottom = offset + height;
2515 DrawRect(draw, paint, r, textSize);
2516 }
2517 if (flags & SkPaint::kStrikeThruText_Flag) {
2518 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2519 start.fY);
2520 r.fTop = offset;
2521 r.fBottom = offset + height;
2522 DrawRect(draw, paint, r, textSize);
2523 }
2524 }
2525}
2526
reed@google.come0d9ce82014-04-23 04:00:17 +00002527void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2528 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002529 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002530
2531 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002532 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002533 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002534 DrawTextDecorations(iter, dfp.paint(),
2535 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002536 }
2537
reed@google.com4e2b3d32011-04-07 14:18:59 +00002538 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002539}
2540
reed@google.come0d9ce82014-04-23 04:00:17 +00002541void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2542 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002543 SkPoint textOffset = SkPoint::Make(0, 0);
2544
halcanary96fcdcc2015-08-27 07:41:13 -07002545 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002546
reed@android.com8a1c16f2008-12-17 15:59:43 +00002547 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002548 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002549 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002550 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002551 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002552
reed@google.com4e2b3d32011-04-07 14:18:59 +00002553 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002554}
2555
reed@google.come0d9ce82014-04-23 04:00:17 +00002556void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2557 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002558
2559 SkPoint textOffset = SkPoint::Make(0, constY);
2560
halcanary96fcdcc2015-08-27 07:41:13 -07002561 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002562
reed@android.com8a1c16f2008-12-17 15:59:43 +00002563 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002564 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002565 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002566 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002567 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002568
reed@google.com4e2b3d32011-04-07 14:18:59 +00002569 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002570}
2571
reed@google.come0d9ce82014-04-23 04:00:17 +00002572void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2573 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002574 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002575
reed@android.com8a1c16f2008-12-17 15:59:43 +00002576 while (iter.next()) {
2577 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002578 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002579 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002580
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002581 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002582}
2583
fmalita00d5c2c2014-08-21 08:53:26 -07002584void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2585 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002586
fmalita85d5eb92015-03-04 11:20:12 -08002587 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002588 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002589 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002590 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002591 SkRect tmp;
2592 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2593 return;
2594 }
2595 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002596 }
2597
fmalita024f9962015-03-03 19:08:17 -08002598 // We cannot filter in the looper as we normally do, because the paint is
2599 // incomplete at this point (text-related attributes are embedded within blob run paints).
2600 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002601 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002602
fmalita85d5eb92015-03-04 11:20:12 -08002603 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002604
fmalitaaa1b9122014-08-28 14:32:24 -07002605 while (iter.next()) {
2606 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002607 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002608 }
2609
fmalitaaa1b9122014-08-28 14:32:24 -07002610 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002611
2612 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002613}
2614
reed@google.come0d9ce82014-04-23 04:00:17 +00002615// These will become non-virtual, so they always call the (virtual) onDraw... method
2616void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2617 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002618 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002619 this->onDrawText(text, byteLength, x, y, paint);
2620}
2621void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2622 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002623 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002624 this->onDrawPosText(text, byteLength, pos, paint);
2625}
2626void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2627 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002628 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002629 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2630}
2631void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2632 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002633 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002634 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2635}
fmalita00d5c2c2014-08-21 08:53:26 -07002636void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2637 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002638 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002639 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002640 this->onDrawTextBlob(blob, x, y, paint);
2641 }
2642}
reed@google.come0d9ce82014-04-23 04:00:17 +00002643
reed41af9662015-01-05 07:49:08 -08002644void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2645 const SkPoint verts[], const SkPoint texs[],
2646 const SkColor colors[], SkXfermode* xmode,
2647 const uint16_t indices[], int indexCount,
2648 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002649 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002650 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002651
reed@android.com8a1c16f2008-12-17 15:59:43 +00002652 while (iter.next()) {
2653 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002654 colors, xmode, indices, indexCount,
2655 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002656 }
reed@google.com4b226022011-01-11 18:32:13 +00002657
reed@google.com4e2b3d32011-04-07 14:18:59 +00002658 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002659}
2660
dandovb3c9d1c2014-08-12 08:34:29 -07002661void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2662 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002663 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002664 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002665 return;
2666 }
mtklein6cfa73a2014-08-13 13:33:49 -07002667
dandovecfff212014-08-04 10:02:00 -07002668 // Since a patch is always within the convex hull of the control points, we discard it when its
2669 // bounding rectangle is completely outside the current clip.
2670 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002671 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002672 if (this->quickReject(bounds)) {
2673 return;
2674 }
mtklein6cfa73a2014-08-13 13:33:49 -07002675
dandovb3c9d1c2014-08-12 08:34:29 -07002676 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2677}
2678
2679void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2680 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2681
halcanary96fcdcc2015-08-27 07:41:13 -07002682 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002683
dandovecfff212014-08-04 10:02:00 -07002684 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002685 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002686 }
mtklein6cfa73a2014-08-13 13:33:49 -07002687
dandovecfff212014-08-04 10:02:00 -07002688 LOOPER_END
2689}
2690
reeda8db7282015-07-07 10:22:31 -07002691void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2692 if (dr) {
2693 if (x || y) {
2694 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2695 this->onDrawDrawable(dr, &matrix);
2696 } else {
halcanary96fcdcc2015-08-27 07:41:13 -07002697 this->onDrawDrawable(dr, nullptr);
reeda8db7282015-07-07 10:22:31 -07002698 }
reed6a070dc2014-11-11 19:36:09 -08002699 }
2700}
2701
reeda8db7282015-07-07 10:22:31 -07002702void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2703 if (dr) {
2704 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002705 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002706 }
2707 this->onDrawDrawable(dr, matrix);
2708 }
2709}
2710
2711void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2712 SkRect bounds = dr->getBounds();
2713 if (matrix) {
2714 matrix->mapRect(&bounds);
2715 }
2716 if (this->quickReject(bounds)) {
2717 return;
2718 }
2719 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002720}
2721
reed71c3c762015-06-24 10:29:17 -07002722void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2723 const SkColor colors[], int count, SkXfermode::Mode mode,
2724 const SkRect* cull, const SkPaint* paint) {
2725 if (cull && this->quickReject(*cull)) {
2726 return;
2727 }
2728
2729 SkPaint pnt;
2730 if (paint) {
2731 pnt = *paint;
2732 }
2733
halcanary96fcdcc2015-08-27 07:41:13 -07002734 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002735 while (iter.next()) {
2736 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2737 }
2738 LOOPER_END
2739}
2740
reed@android.com8a1c16f2008-12-17 15:59:43 +00002741//////////////////////////////////////////////////////////////////////////////
2742// These methods are NOT virtual, and therefore must call back into virtual
2743// methods, rather than actually drawing themselves.
2744//////////////////////////////////////////////////////////////////////////////
2745
2746void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002747 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002748 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002749 SkPaint paint;
2750
2751 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002752 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002753 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002754 }
2755 this->drawPaint(paint);
2756}
2757
reed@android.com845fdac2009-06-23 03:01:32 +00002758void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002759 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002760 SkPaint paint;
2761
2762 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002763 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002764 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002765 }
2766 this->drawPaint(paint);
2767}
2768
2769void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002770 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002771 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002772
reed@android.com8a1c16f2008-12-17 15:59:43 +00002773 pt.set(x, y);
2774 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2775}
2776
2777void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002778 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002779 SkPoint pt;
2780 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002781
reed@android.com8a1c16f2008-12-17 15:59:43 +00002782 pt.set(x, y);
2783 paint.setColor(color);
2784 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2785}
2786
2787void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2788 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002789 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002791
reed@android.com8a1c16f2008-12-17 15:59:43 +00002792 pts[0].set(x0, y0);
2793 pts[1].set(x1, y1);
2794 this->drawPoints(kLines_PointMode, 2, pts, paint);
2795}
2796
2797void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2798 SkScalar right, SkScalar bottom,
2799 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002800 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002801 SkRect r;
2802
2803 r.set(left, top, right, bottom);
2804 this->drawRect(r, paint);
2805}
2806
2807void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2808 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002809 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002810 if (radius < 0) {
2811 radius = 0;
2812 }
2813
2814 SkRect r;
2815 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002816 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817}
2818
2819void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2820 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002821 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002822 if (rx > 0 && ry > 0) {
2823 if (paint.canComputeFastBounds()) {
2824 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002825 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002826 return;
2827 }
2828 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002829 SkRRect rrect;
2830 rrect.setRectXY(r, rx, ry);
2831 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002832 } else {
2833 this->drawRect(r, paint);
2834 }
2835}
2836
reed@android.com8a1c16f2008-12-17 15:59:43 +00002837void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2838 SkScalar sweepAngle, bool useCenter,
2839 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002840 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002841 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2842 this->drawOval(oval, paint);
2843 } else {
2844 SkPath path;
2845 if (useCenter) {
2846 path.moveTo(oval.centerX(), oval.centerY());
2847 }
2848 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2849 if (useCenter) {
2850 path.close();
2851 }
2852 this->drawPath(path, paint);
2853 }
2854}
2855
2856void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2857 const SkPath& path, SkScalar hOffset,
2858 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002859 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002860 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002861
reed@android.com8a1c16f2008-12-17 15:59:43 +00002862 matrix.setTranslate(hOffset, vOffset);
2863 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2864}
2865
reed@android.comf76bacf2009-05-13 14:00:33 +00002866///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002867
2868/**
2869 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2870 * against the playback cost of recursing into the subpicture to get at its actual ops.
2871 *
2872 * For now we pick a conservatively small value, though measurement (and other heuristics like
2873 * the type of ops contained) may justify changing this value.
2874 */
2875#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002876
reedd5fa1a42014-08-09 11:08:05 -07002877void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002878 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002879 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002880 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002881 matrix = nullptr;
reedd5fa1a42014-08-09 11:08:05 -07002882 }
reed1c2c4412015-04-30 13:09:24 -07002883 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2884 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2885 picture->playback(this);
2886 } else {
2887 this->onDrawPicture(picture, matrix, paint);
2888 }
reedd5fa1a42014-08-09 11:08:05 -07002889 }
2890}
robertphillips9b14f262014-06-04 05:40:44 -07002891
reedd5fa1a42014-08-09 11:08:05 -07002892void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2893 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002894 if (!paint || paint->canComputeFastBounds()) {
2895 SkRect bounds = picture->cullRect();
2896 if (paint) {
2897 paint->computeFastBounds(bounds, &bounds);
2898 }
2899 if (matrix) {
2900 matrix->mapRect(&bounds);
2901 }
2902 if (this->quickReject(bounds)) {
2903 return;
2904 }
2905 }
2906
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002907 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002908 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002909 // Canvas has to first give the device the opportunity to render
2910 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002911 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002912 return; // the device has rendered the entire picture
2913 }
2914 }
2915
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002916 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002917 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002918}
2919
reed@android.com8a1c16f2008-12-17 15:59:43 +00002920///////////////////////////////////////////////////////////////////////////////
2921///////////////////////////////////////////////////////////////////////////////
2922
2923SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002924 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002925
2926 SkASSERT(canvas);
2927
2928 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2929 fDone = !fImpl->next();
2930}
2931
2932SkCanvas::LayerIter::~LayerIter() {
2933 fImpl->~SkDrawIter();
2934}
2935
2936void SkCanvas::LayerIter::next() {
2937 fDone = !fImpl->next();
2938}
2939
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002940SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002941 return fImpl->getDevice();
2942}
2943
2944const SkMatrix& SkCanvas::LayerIter::matrix() const {
2945 return fImpl->getMatrix();
2946}
2947
2948const SkPaint& SkCanvas::LayerIter::paint() const {
2949 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002950 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002951 paint = &fDefaultPaint;
2952 }
2953 return *paint;
2954}
2955
2956const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2957int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2958int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002959
2960///////////////////////////////////////////////////////////////////////////////
2961
fmalitac3b589a2014-06-05 12:40:07 -07002962SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002963
2964///////////////////////////////////////////////////////////////////////////////
2965
2966static bool supported_for_raster_canvas(const SkImageInfo& info) {
2967 switch (info.alphaType()) {
2968 case kPremul_SkAlphaType:
2969 case kOpaque_SkAlphaType:
2970 break;
2971 default:
2972 return false;
2973 }
2974
2975 switch (info.colorType()) {
2976 case kAlpha_8_SkColorType:
2977 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002978 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002979 break;
2980 default:
2981 return false;
2982 }
2983
2984 return true;
2985}
2986
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002987SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2988 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002989 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002990 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002991
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002992 SkBitmap bitmap;
2993 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002994 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002995 }
halcanary385fe4d2015-08-26 13:07:48 -07002996 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002997}
reedd5fa1a42014-08-09 11:08:05 -07002998
2999///////////////////////////////////////////////////////////////////////////////
3000
3001SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003002 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003003 : fCanvas(canvas)
3004 , fSaveCount(canvas->getSaveCount())
3005{
bsalomon49f085d2014-09-05 13:34:00 -07003006 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003007 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003008 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003009 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003010 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003011 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003012 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003013 canvas->save();
3014 }
mtklein6cfa73a2014-08-13 13:33:49 -07003015
bsalomon49f085d2014-09-05 13:34:00 -07003016 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003017 canvas->concat(*matrix);
3018 }
3019}
3020
3021SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3022 fCanvas->restoreToCount(fSaveCount);
3023}