blob: a4acbdc94d118e2d6fe1b3cee023416f4a9efe28 [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
reed0575cb22016-01-07 08:15:10 -0800117
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 }
reed0575cb22016-01-07 08:15:10 -0800484 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp, 0),
reed76033be2015-03-14 10:54:31 -0700485 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700486 fTempLayerForImageFilter = true;
487 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000488 }
489
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000490 if (SkDrawLooper* looper = paint.getLooper()) {
491 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
492 looper->contextSize());
493 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000494 fIsSimple = false;
495 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700496 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000497 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700498 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000499 }
piotaixrb5fae932014-09-24 13:03:30 -0700500
reed4a8126e2014-09-22 07:29:03 -0700501 uint32_t oldFlags = paint.getFlags();
502 fNewPaintFlags = filter_paint_flags(props, oldFlags);
503 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700504 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700505 paint->setFlags(fNewPaintFlags);
506 fPaint = paint;
507 // if we're not simple, doNext() will take care of calling setFlags()
508 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000509 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000510
reed@android.com8a1c16f2008-12-17 15:59:43 +0000511 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700512 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000513 fCanvas->internalRestore();
514 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000515 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000517
reed@google.com4e2b3d32011-04-07 14:18:59 +0000518 const SkPaint& paint() const {
519 SkASSERT(fPaint);
520 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000522
reed@google.com129ec222012-05-15 13:24:09 +0000523 bool next(SkDrawFilter::Type drawType) {
524 if (fDone) {
525 return false;
526 } else if (fIsSimple) {
527 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000528 return !fPaint->nothingToDraw();
529 } else {
530 return this->doNext(drawType);
531 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000532 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000533
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534private:
reeddbc3cef2015-04-29 12:18:57 -0700535 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
536 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000537 SkCanvas* fCanvas;
538 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000539 SkDrawFilter* fFilter;
540 const SkPaint* fPaint;
541 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700542 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700543 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000544 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000545 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000546 SkDrawLooper::Context* fLooperContext;
547 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000548
549 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000550};
551
reed@google.com129ec222012-05-15 13:24:09 +0000552bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700553 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000554 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700555 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000556
reeddbc3cef2015-04-29 12:18:57 -0700557 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
558 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700559 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000560
reed5c476fb2015-04-20 08:04:21 -0700561 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700562 paint->setImageFilter(nullptr);
563 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000564 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000565
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000566 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000567 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000568 return false;
569 }
570 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000571 if (!fFilter->filter(paint, drawType)) {
572 fDone = true;
573 return false;
574 }
halcanary96fcdcc2015-08-27 07:41:13 -0700575 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000576 // no looper means we only draw once
577 fDone = true;
578 }
579 }
580 fPaint = paint;
581
582 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000583 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000584 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000585 }
586
587 // call this after any possible paint modifiers
588 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700589 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000590 return false;
591 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000592 return true;
593}
594
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595////////// macros to place around the internal draw calls //////////////////
596
reed262a71b2015-12-05 13:07:27 -0800597#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
598 this->predrawNotify(); \
599 AutoDrawLooper looper(this, fProps, paint, skipLayerForFilter, bounds); \
600 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
601 SkDrawIter iter(this);
602
603
reed@google.com8926b162012-03-23 15:36:36 +0000604#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000605 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700606 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000607 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000608 SkDrawIter iter(this);
609
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000610#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000611 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700612 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000613 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000615
reedc83a2972015-07-16 07:40:45 -0700616#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
617 this->predrawNotify(bounds, &paint, auxOpaque); \
618 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
619 while (looper.next(type)) { \
620 SkDrawIter iter(this);
621
reed@google.com4e2b3d32011-04-07 14:18:59 +0000622#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000623
624////////////////////////////////////////////////////////////////////////////
625
mtkleinfeaadee2015-04-08 11:25:48 -0700626void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
627 this->restoreToCount(1);
628 fCachedLocalClipBounds.setEmpty();
629 fCachedLocalClipBoundsDirty = true;
630 fClipStack->reset();
631 fMCRec->reset(bounds);
632
633 // We're peering through a lot of structs here. Only at this scope do we
634 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
635 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
636}
637
reedd9544982014-09-09 18:46:22 -0700638SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800639 if (device && device->forceConservativeRasterClip()) {
640 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
641 }
642 // Since init() is only called once by our constructors, it is safe to perform this
643 // const-cast.
644 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
645
reed@google.comc0784db2013-12-13 21:16:12 +0000646 fCachedLocalClipBounds.setEmpty();
647 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000648 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000649 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700650 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800651 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700652 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653
halcanary385fe4d2015-08-26 13:07:48 -0700654 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700655
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700657 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658
reeda499f902015-05-01 09:34:31 -0700659 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
660 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
halcanary96fcdcc2015-08-27 07:41:13 -0700661 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700662
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664
halcanary96fcdcc2015-08-27 07:41:13 -0700665 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000666
reedf92c8662014-08-18 08:02:43 -0700667 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700668 // The root device and the canvas should always have the same pixel geometry
669 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700670 device->onAttachToCanvas(this);
671 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800672 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700673 }
674 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000675}
676
reed@google.comcde92112011-07-06 20:00:52 +0000677SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000678 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700679 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800680 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000681{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000682 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000683
halcanary96fcdcc2015-08-27 07:41:13 -0700684 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000685}
686
reedd9544982014-09-09 18:46:22 -0700687static SkBitmap make_nopixels(int width, int height) {
688 SkBitmap bitmap;
689 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
690 return bitmap;
691}
692
693class SkNoPixelsBitmapDevice : public SkBitmapDevice {
694public:
robertphillipsfcf78292015-06-19 11:49:52 -0700695 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
696 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800697 {
698 this->setOrigin(bounds.x(), bounds.y());
699 }
reedd9544982014-09-09 18:46:22 -0700700
701private:
piotaixrb5fae932014-09-24 13:03:30 -0700702
reedd9544982014-09-09 18:46:22 -0700703 typedef SkBitmapDevice INHERITED;
704};
705
reed96a857e2015-01-25 10:33:58 -0800706SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000707 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800708 , fProps(SkSurfacePropsCopyOrDefault(props))
reed42b73eb2015-11-20 13:42:42 -0800709 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000710{
711 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700712
halcanary385fe4d2015-08-26 13:07:48 -0700713 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
714 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700715}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000716
reed78e27682014-11-19 08:04:34 -0800717SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700718 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700719 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800720 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700721{
722 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700723
halcanary385fe4d2015-08-26 13:07:48 -0700724 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700725}
726
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000727SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000728 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700729 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800730 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000731{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700733
reedd9544982014-09-09 18:46:22 -0700734 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000735}
736
robertphillipsfcf78292015-06-19 11:49:52 -0700737SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
738 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700739 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800740 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700741{
742 inc_canvas();
743
744 this->init(device, flags);
745}
746
reed4a8126e2014-09-22 07:29:03 -0700747SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700748 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700749 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800750 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700751{
752 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700753
halcanary385fe4d2015-08-26 13:07:48 -0700754 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700755 this->init(device, kDefault_InitFlags);
756}
reed29c857d2014-09-21 10:25:07 -0700757
reed4a8126e2014-09-22 07:29:03 -0700758SkCanvas::SkCanvas(const SkBitmap& bitmap)
759 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
760 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800761 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700762{
763 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700764
halcanary385fe4d2015-08-26 13:07:48 -0700765 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700766 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000767}
768
769SkCanvas::~SkCanvas() {
770 // free up the contents of our deque
771 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000772
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773 this->internalRestore(); // restore the last, since we're going away
774
halcanary385fe4d2015-08-26 13:07:48 -0700775 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000776
reed@android.com8a1c16f2008-12-17 15:59:43 +0000777 dec_canvas();
778}
779
reed@android.com8a1c16f2008-12-17 15:59:43 +0000780SkDrawFilter* SkCanvas::getDrawFilter() const {
781 return fMCRec->fFilter;
782}
783
784SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700785 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000786 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
787 return filter;
788}
789
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000790SkMetaData& SkCanvas::getMetaData() {
791 // metadata users are rare, so we lazily allocate it. If that changes we
792 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700793 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000794 fMetaData = new SkMetaData;
795 }
796 return *fMetaData;
797}
798
reed@android.com8a1c16f2008-12-17 15:59:43 +0000799///////////////////////////////////////////////////////////////////////////////
800
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000801void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000802 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000803 if (device) {
804 device->flush();
805 }
806}
807
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000808SkISize SkCanvas::getTopLayerSize() const {
809 SkBaseDevice* d = this->getTopDevice();
810 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
811}
812
813SkIPoint SkCanvas::getTopLayerOrigin() const {
814 SkBaseDevice* d = this->getTopDevice();
815 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
816}
817
818SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000819 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000820 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
821}
822
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000823SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000825 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000826 SkASSERT(rec && rec->fLayer);
827 return rec->fLayer->fDevice;
828}
829
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000830SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000831 if (updateMatrixClip) {
832 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
833 }
reed@google.com9266fed2011-03-30 00:18:03 +0000834 return fMCRec->fTopLayer->fDevice;
835}
836
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000837bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
838 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
839 return false;
840 }
841
842 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700843 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700844 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000845 return false;
846 }
847 weAllocated = true;
848 }
849
reedcf01e312015-05-23 19:14:51 -0700850 SkAutoPixmapUnlock unlocker;
851 if (bitmap->requestLock(&unlocker)) {
852 const SkPixmap& pm = unlocker.pixmap();
853 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
854 return true;
855 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000856 }
857
858 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700859 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000860 }
861 return false;
862}
reed@google.com51df9e32010-12-23 19:29:18 +0000863
bsalomon@google.comc6980972011-11-02 19:57:21 +0000864bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000865 SkIRect r = srcRect;
866 const SkISize size = this->getBaseLayerSize();
867 if (!r.intersect(0, 0, size.width(), size.height())) {
868 bitmap->reset();
869 return false;
870 }
871
reed84825042014-09-02 12:50:45 -0700872 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000873 // bitmap will already be reset.
874 return false;
875 }
876 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
877 bitmap->reset();
878 return false;
879 }
880 return true;
881}
882
reed96472de2014-12-10 09:53:42 -0800883bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000884 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000885 if (!device) {
886 return false;
887 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000888 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800889
reed96472de2014-12-10 09:53:42 -0800890 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
891 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000892 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000893 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000894
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000895 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800896 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000897}
898
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000899bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
900 if (bitmap.getTexture()) {
901 return false;
902 }
reedcf01e312015-05-23 19:14:51 -0700903
904 SkAutoPixmapUnlock unlocker;
905 if (bitmap.requestLock(&unlocker)) {
906 const SkPixmap& pm = unlocker.pixmap();
907 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000908 }
909 return false;
910}
911
912bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
913 int x, int y) {
914 switch (origInfo.colorType()) {
915 case kUnknown_SkColorType:
916 case kIndex_8_SkColorType:
917 return false;
918 default:
919 break;
920 }
halcanary96fcdcc2015-08-27 07:41:13 -0700921 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000922 return false;
923 }
924
925 const SkISize size = this->getBaseLayerSize();
926 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
927 if (!target.intersect(0, 0, size.width(), size.height())) {
928 return false;
929 }
930
931 SkBaseDevice* device = this->getDevice();
932 if (!device) {
933 return false;
934 }
935
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000936 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700937 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000938
939 // if x or y are negative, then we have to adjust pixels
940 if (x > 0) {
941 x = 0;
942 }
943 if (y > 0) {
944 y = 0;
945 }
946 // here x,y are either 0 or negative
947 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
948
reed4af35f32014-06-27 17:47:49 -0700949 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700950 const bool completeOverwrite = info.dimensions() == size;
951 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700952
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000953 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000954 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000955}
reed@google.com51df9e32010-12-23 19:29:18 +0000956
junov@google.com4370aed2012-01-18 16:21:08 +0000957SkCanvas* SkCanvas::canvasForDrawIter() {
958 return this;
959}
960
reed@android.com8a1c16f2008-12-17 15:59:43 +0000961//////////////////////////////////////////////////////////////////////////////
962
reed@android.com8a1c16f2008-12-17 15:59:43 +0000963void SkCanvas::updateDeviceCMCache() {
964 if (fDeviceCMDirty) {
965 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700966 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000968
halcanary96fcdcc2015-08-27 07:41:13 -0700969 if (nullptr == layer->fNext) { // only one layer
970 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000972 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973 do {
reed687fa1c2015-04-07 08:00:56 -0700974 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700975 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976 }
977 fDeviceCMDirty = false;
978 }
979}
980
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981///////////////////////////////////////////////////////////////////////////////
982
reed2ff1fce2014-12-11 07:07:37 -0800983void SkCanvas::checkForDeferredSave() {
984 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800985 this->doSave();
986 }
987}
988
reedf0090cb2014-11-26 08:55:51 -0800989int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800990#ifdef SK_DEBUG
991 int count = 0;
992 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
993 for (;;) {
994 const MCRec* rec = (const MCRec*)iter.next();
995 if (!rec) {
996 break;
997 }
998 count += 1 + rec->fDeferredSaveCount;
999 }
1000 SkASSERT(count == fSaveCount);
1001#endif
1002 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -08001003}
1004
1005int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -08001006 fSaveCount += 1;
1007 fMCRec->fDeferredSaveCount += 1;
1008 return this->getSaveCount() - 1; // return our prev value
1009}
1010
1011void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001012 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001013
1014 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1015 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001016 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001017}
1018
1019void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001020 if (fMCRec->fDeferredSaveCount > 0) {
1021 SkASSERT(fSaveCount > 1);
1022 fSaveCount -= 1;
1023 fMCRec->fDeferredSaveCount -= 1;
1024 } else {
1025 // check for underflow
1026 if (fMCStack.count() > 1) {
1027 this->willRestore();
1028 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001029 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001030 this->internalRestore();
1031 this->didRestore();
1032 }
reedf0090cb2014-11-26 08:55:51 -08001033 }
1034}
1035
1036void SkCanvas::restoreToCount(int count) {
1037 // sanity check
1038 if (count < 1) {
1039 count = 1;
1040 }
mtkleinf0f14112014-12-12 08:46:25 -08001041
reedf0090cb2014-11-26 08:55:51 -08001042 int n = this->getSaveCount() - count;
1043 for (int i = 0; i < n; ++i) {
1044 this->restore();
1045 }
1046}
1047
reed2ff1fce2014-12-11 07:07:37 -08001048void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001049 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001050 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001051 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001052
reed687fa1c2015-04-07 08:00:56 -07001053 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054}
1055
reed4960eee2015-12-18 07:09:18 -08001056bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001057#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001058 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
reed@google.comb93ba452014-03-10 19:47:58 +00001059#else
1060 return true;
1061#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062}
1063
reed4960eee2015-12-18 07:09:18 -08001064bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
reed9b3aa542015-03-11 08:47:12 -07001065 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001066 SkIRect clipBounds;
1067 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001068 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001069 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001070
reed96e657d2015-03-10 17:30:07 -07001071 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1072
senorblanco87e066e2015-10-28 11:23:36 -07001073// This is a temporary hack, until individual filters can do their own
1074// bloating, when this will be removed.
1075#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
1076 SkRect storage;
1077#endif
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001078 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -07001079 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco87e066e2015-10-28 11:23:36 -07001080#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
1081 if (bounds && imageFilter->canComputeFastBounds()) {
1082 imageFilter->computeFastBounds(*bounds, &storage);
1083 bounds = &storage;
1084 } else {
1085 bounds = nullptr;
1086 }
senorblancodb64af32015-12-09 10:11:43 -08001087#else
1088 if (bounds && !imageFilter->canComputeFastBounds()) {
1089 bounds = nullptr;
1090 }
senorblanco87e066e2015-10-28 11:23:36 -07001091#endif
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001092 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001093 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001094 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001095 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001096
reed96e657d2015-03-10 17:30:07 -07001097 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098 r.roundOut(&ir);
1099 // early exit if the layer's bounds are clipped out
1100 if (!ir.intersect(clipBounds)) {
reed4960eee2015-12-18 07:09:18 -08001101 if (BoundsAffectsClip(saveLayerFlags)) {
reed9b3aa542015-03-11 08:47:12 -07001102 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001103 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001104 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001105 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106 }
1107 } else { // no user bounds, so just use the clip
1108 ir = clipBounds;
1109 }
reed180aec42015-03-11 10:39:04 -07001110 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111
reed4960eee2015-12-18 07:09:18 -08001112 if (BoundsAffectsClip(saveLayerFlags)) {
reed180aec42015-03-11 10:39:04 -07001113 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -07001114 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -07001115 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001116 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001117 }
1118
1119 if (intersection) {
1120 *intersection = ir;
1121 }
1122 return true;
1123}
1124
reedbada1882015-12-21 13:09:44 -08001125#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS
reed4960eee2015-12-18 07:09:18 -08001126uint32_t SkCanvas::SaveFlagsToSaveLayerFlags(SaveFlags flags) {
1127 uint32_t layerFlags = 0;
1128
1129 if (0 == (flags & kClipToLayer_SaveFlag)) {
1130 layerFlags |= kDontClipToLayer_PrivateSaveLayerFlag;
reedd990e2f2014-12-22 11:58:30 -08001131 }
reed4960eee2015-12-18 07:09:18 -08001132 if (0 == (flags & kHasAlphaLayer_SaveFlag)) {
1133 layerFlags |= kIsOpaque_SaveLayerFlag;
1134 }
1135 return layerFlags;
1136}
scroggoffe031e2016-01-04 07:16:32 -08001137
1138uint32_t SkCanvas::SaveLayerFlagsToSaveFlags(SaveLayerFlags layerFlags) {
1139 uint32_t saveFlags = 0;
1140
1141 if (0 == (layerFlags & kDontClipToLayer_PrivateSaveLayerFlag)) {
1142 saveFlags |= kClipToLayer_SaveFlag;
1143 }
1144 if (0 == (layerFlags & kIsOpaque_SaveLayerFlag)) {
1145 saveFlags |= kHasAlphaLayer_SaveFlag;
1146 }
1147 return saveFlags;
1148}
reedbada1882015-12-21 13:09:44 -08001149#endif
reed4960eee2015-12-18 07:09:18 -08001150
reed4960eee2015-12-18 07:09:18 -08001151int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1152 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001153}
1154
reedbada1882015-12-21 13:09:44 -08001155#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS
reed2ff1fce2014-12-11 07:07:37 -08001156int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reed4960eee2015-12-18 07:09:18 -08001157 return this->saveLayer(SaveLayerRec(bounds, paint, SaveFlagsToSaveLayerFlags(flags)));
reed@google.com8926b162012-03-23 15:36:36 +00001158}
reedbada1882015-12-21 13:09:44 -08001159#endif
reed@google.com8926b162012-03-23 15:36:36 +00001160
reed70ee31b2015-12-10 13:44:45 -08001161int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
reed4960eee2015-12-18 07:09:18 -08001162 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1163}
1164
1165int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1166 SaveLayerRec rec(origRec);
1167 if (gIgnoreSaveLayerBounds) {
1168 rec.fBounds = nullptr;
1169 }
1170 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1171 fSaveCount += 1;
1172 this->internalSaveLayer(rec, strategy);
1173 return this->getSaveCount() - 1;
reed70ee31b2015-12-10 13:44:45 -08001174}
1175
reed0575cb22016-01-07 08:15:10 -08001176static void draw_filter_into_device(SkBaseDevice* src, SkImageFilter* filter, SkBaseDevice* dst) {
robertphillips7354a4b2015-12-16 05:08:27 -08001177
1178 SkBitmap srcBM;
1179
1180#if SK_SUPPORT_GPU
1181 GrRenderTarget* srcRT = src->accessRenderTarget();
1182 if (srcRT && !srcRT->asTexture() && dst->accessRenderTarget()) {
1183 // When both the src & the dst are on the gpu but the src doesn't have a texture,
1184 // we create a temporary texture for the draw.
1185 // TODO: we should actually only copy the portion of the source needed to apply the image
1186 // filter
1187 GrContext* context = srcRT->getContext();
1188 SkAutoTUnref<GrTexture> tex(context->textureProvider()->createTexture(srcRT->desc(), true));
1189
1190 context->copySurface(tex, srcRT);
1191
1192 GrWrapTextureInBitmap(tex, src->width(), src->height(), src->isOpaque(), &srcBM);
1193 } else
1194#endif
1195 {
1196 srcBM = src->accessBitmap(false);
1197 }
1198
1199 SkCanvas c(dst);
1200
1201 SkPaint p;
reed0575cb22016-01-07 08:15:10 -08001202 p.setImageFilter(filter);
1203 c.drawBitmap(srcBM, 0, 0, &p);
robertphillips7354a4b2015-12-16 05:08:27 -08001204}
reed70ee31b2015-12-10 13:44:45 -08001205
reed4960eee2015-12-18 07:09:18 -08001206void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1207 const SkRect* bounds = rec.fBounds;
1208 const SkPaint* paint = rec.fPaint;
1209 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1210
reed@google.comb93ba452014-03-10 19:47:58 +00001211#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed4960eee2015-12-18 07:09:18 -08001212 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001213#endif
1214
junov@chromium.orga907ac32012-02-24 21:54:07 +00001215 // do this before we create the layer. We don't call the public save() since
1216 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001217 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001218
1219 fDeviceCMDirty = true;
1220
1221 SkIRect ir;
reed4960eee2015-12-18 07:09:18 -08001222 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, paint ? paint->getImageFilter() : nullptr)) {
reed2ff1fce2014-12-11 07:07:37 -08001223 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224 }
1225
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001226 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1227 // the clipRectBounds() call above?
1228 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001229 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001230 }
1231
reed4960eee2015-12-18 07:09:18 -08001232 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001233 SkPixelGeometry geo = fProps.pixelGeometry();
1234 if (paint) {
reed76033be2015-03-14 10:54:31 -07001235 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001236 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001237 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001238 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001239 }
1240 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001241 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1242 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001243
reedb2db8982014-11-13 12:41:02 -08001244 SkBaseDevice* device = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001245 if (nullptr == device) {
reedb2db8982014-11-13 12:41:02 -08001246 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001247 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001248 }
reedb2db8982014-11-13 12:41:02 -08001249
reed61f501f2015-04-29 08:34:00 -07001250 bool forceSpriteOnRestore = false;
1251 {
reed70ee31b2015-12-10 13:44:45 -08001252 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
reed4960eee2015-12-18 07:09:18 -08001253 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
reeddaa57bf2015-05-15 10:39:17 -07001254 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed70ee31b2015-12-10 13:44:45 -08001255 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1256 preserveLCDText, false);
reed61f501f2015-04-29 08:34:00 -07001257 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001258 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001259 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001260 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1261 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
halcanary96fcdcc2015-08-27 07:41:13 -07001262 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001263 SkErrorInternals::SetError(kInternalError_SkError,
1264 "Unable to create device for layer.");
1265 return;
1266 }
1267 forceSpriteOnRestore = true;
1268 }
1269 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001270 }
reed0575cb22016-01-07 08:15:10 -08001271
reed@google.com6f8f2922011-03-04 22:27:10 +00001272 device->setOrigin(ir.fLeft, ir.fTop);
robertphillips7354a4b2015-12-16 05:08:27 -08001273
reed0575cb22016-01-07 08:15:10 -08001274 if (0) {
1275 draw_filter_into_device(fMCRec->fTopLayer->fDevice, nullptr, device);
robertphillips7354a4b2015-12-16 05:08:27 -08001276 }
1277
halcanary385fe4d2015-08-26 13:07:48 -07001278 DeviceCM* layer =
1279 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001280 device->unref();
1281
1282 layer->fNext = fMCRec->fTopLayer;
1283 fMCRec->fLayer = layer;
1284 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285}
1286
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001287int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
reedbada1882015-12-21 13:09:44 -08001288 if (0xFF == alpha) {
1289 return this->saveLayer(bounds, nullptr);
1290 } else {
1291 SkPaint tmpPaint;
1292 tmpPaint.setAlpha(alpha);
1293 return this->saveLayer(bounds, &tmpPaint);
1294 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001295}
1296
reedbada1882015-12-21 13:09:44 -08001297#ifdef SK_SUPPORT_LEGACY_SAVEFLAGS
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1299 SaveFlags flags) {
1300 if (0xFF == alpha) {
halcanary96fcdcc2015-08-27 07:41:13 -07001301 return this->saveLayer(bounds, nullptr, flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 } else {
1303 SkPaint tmpPaint;
1304 tmpPaint.setAlpha(alpha);
1305 return this->saveLayer(bounds, &tmpPaint, flags);
1306 }
1307}
reedbada1882015-12-21 13:09:44 -08001308#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001309
reed@android.com8a1c16f2008-12-17 15:59:43 +00001310void SkCanvas::internalRestore() {
1311 SkASSERT(fMCStack.count() != 0);
1312
1313 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001314 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001315
reed687fa1c2015-04-07 08:00:56 -07001316 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001317
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001318 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 DeviceCM* layer = fMCRec->fLayer; // may be null
1320 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001321 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322
1323 // now do the normal restore()
1324 fMCRec->~MCRec(); // balanced in save()
1325 fMCStack.pop_back();
1326 fMCRec = (MCRec*)fMCStack.back();
1327
1328 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1329 since if we're being recorded, we don't want to record this (the
1330 recorder will have already recorded the restore).
1331 */
bsalomon49f085d2014-09-05 13:34:00 -07001332 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001334 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001335 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001336 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001337 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001338 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001339 delete layer;
reedb679ca82015-04-07 04:40:48 -07001340 } else {
1341 // we're at the root
reeda499f902015-05-01 09:34:31 -07001342 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001343 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001345 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346}
1347
reed4a8126e2014-09-22 07:29:03 -07001348SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001349 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001350 props = &fProps;
1351 }
1352 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001353}
1354
reed4a8126e2014-09-22 07:29:03 -07001355SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001356 SkBaseDevice* dev = this->getDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001357 return dev ? dev->newSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001358}
1359
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001360SkImageInfo SkCanvas::imageInfo() const {
1361 SkBaseDevice* dev = this->getDevice();
1362 if (dev) {
1363 return dev->imageInfo();
1364 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001365 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001366 }
1367}
1368
1369const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001370 SkPixmap pmap;
1371 if (!this->onPeekPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001372 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001373 }
1374 if (info) {
1375 *info = pmap.info();
1376 }
1377 if (rowBytes) {
1378 *rowBytes = pmap.rowBytes();
1379 }
1380 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001381}
1382
reed884e97c2015-05-26 11:31:54 -07001383bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001384 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001385 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001386}
1387
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001388void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001389 SkPixmap pmap;
1390 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001391 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001392 }
1393 if (info) {
1394 *info = pmap.info();
1395 }
1396 if (rowBytes) {
1397 *rowBytes = pmap.rowBytes();
1398 }
1399 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001400 *origin = this->getTopDevice(false)->getOrigin();
1401 }
reed884e97c2015-05-26 11:31:54 -07001402 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001403}
1404
reed884e97c2015-05-26 11:31:54 -07001405bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001406 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001407 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001408}
1409
reed@android.com8a1c16f2008-12-17 15:59:43 +00001410/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001411
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001412void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001413 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001415 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416 paint = &tmp;
1417 }
reed@google.com4b226022011-01-11 18:32:13 +00001418
reed@google.com8926b162012-03-23 15:36:36 +00001419 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001421 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001422 paint = &looper.paint();
1423 SkImageFilter* filter = paint->getImageFilter();
1424 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001425 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001426 SkImageFilter::DeviceProxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001427 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001428 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001429 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001430 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001431 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblancodb64af32015-12-09 10:11:43 -08001432#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001433 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancodb64af32015-12-09 10:11:43 -08001434#else
1435 SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
1436#endif
senorblancobe129b22014-08-08 07:14:35 -07001437 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reedc9b5f8b2015-10-22 13:20:20 -07001438 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(),
1439 SkImageFilter::kApprox_SizeConstraint);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001440 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001441 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001442 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001443 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1444 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001445 }
reed61f501f2015-04-29 08:34:00 -07001446 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001447 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001448 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001449 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001450 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001451 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001452 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001453 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001454}
1455
reed32704672015-12-16 08:27:10 -08001456/////////////////////////////////////////////////////////////////////////////
reedda420b92015-12-16 08:38:15 -08001457
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001458void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001459 SkMatrix m;
1460 m.setTranslate(dx, dy);
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::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001465 SkMatrix m;
1466 m.setScale(sx, sy);
1467 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468}
1469
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001470void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001471 SkMatrix m;
1472 m.setRotate(degrees);
1473 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001474}
1475
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001476void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001477 SkMatrix m;
1478 m.setSkew(sx, sy);
1479 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001480}
1481
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001482void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001483 if (matrix.isIdentity()) {
1484 return;
1485 }
1486
reed2ff1fce2014-12-11 07:07:37 -08001487 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001489 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001490 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001491
1492 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001493}
1494
reed86a17e72015-05-14 12:25:22 -07001495void SkCanvas::setMatrix(const SkMatrix& matrix) {
1496 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001497 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001498 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001499 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001500 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501}
1502
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503void SkCanvas::resetMatrix() {
1504 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001505
reed@android.com8a1c16f2008-12-17 15:59:43 +00001506 matrix.reset();
1507 this->setMatrix(matrix);
1508}
1509
1510//////////////////////////////////////////////////////////////////////////////
1511
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001512void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001513 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001514 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1515 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001516}
1517
1518void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001519#ifdef SK_ENABLE_CLIP_QUICKREJECT
1520 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001521 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001522 return false;
1523 }
1524
reed@google.com3b3e8952012-08-16 20:53:31 +00001525 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001526 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001527 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001528
reed687fa1c2015-04-07 08:00:56 -07001529 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001530 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001531 }
1532 }
1533#endif
1534
bsalomonac8cabd2015-11-20 18:53:07 -08001535 if (!fAllowSoftClip) {
1536 edgeStyle = kHard_ClipEdgeStyle;
1537 }
reed90ba0952015-11-20 13:42:47 -08001538
reedc64eff52015-11-21 12:39:45 -08001539 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1540 SkRect devR;
1541 if (rectStaysRect) {
1542 fMCRec->fMatrix.mapRect(&devR, rect);
1543 }
bsalomonac8cabd2015-11-20 18:53:07 -08001544
reedc64eff52015-11-21 12:39:45 -08001545 // Check if we can quick-accept the clip call (and do nothing)
1546 //
1547 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1548 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1549 // might allow lazy save/restores to eliminate entire save/restore blocks.
1550 //
1551 if (SkRegion::kIntersect_Op == op &&
1552 kHard_ClipEdgeStyle == edgeStyle
1553 && rectStaysRect)
1554 {
1555 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1556#if 0
1557 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1558 rect.left(), rect.top(), rect.right(), rect.bottom());
1559#endif
1560 return;
1561 }
1562 }
1563
1564 AutoValidateClip avc(this);
1565
1566 fDeviceCMDirty = true;
1567 fCachedLocalClipBoundsDirty = true;
1568
1569 if (rectStaysRect) {
1570 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1571 fClipStack->clipDevRect(devR, op, isAA);
1572 fMCRec->fRasterClip.op(devR, this->getBaseLayerSize(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001573 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001574 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001575 // and clip against that, since it can handle any matrix. However, to
1576 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1577 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001578 SkPath path;
1579
1580 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001581 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001582 }
1583}
1584
reed73e714e2014-09-04 09:02:23 -07001585static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1586 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001587 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001588}
1589
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001590void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001591 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001592 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001593 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001594 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1595 } else {
1596 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001597 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001598}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001599
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001600void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001601 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001602 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001603 AutoValidateClip avc(this);
1604
1605 fDeviceCMDirty = true;
1606 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001607 if (!fAllowSoftClip) {
1608 edgeStyle = kHard_ClipEdgeStyle;
1609 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001610
reed687fa1c2015-04-07 08:00:56 -07001611 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001612
robertphillips125f19a2015-11-23 09:00:05 -08001613 fMCRec->fRasterClip.op(transformedRRect, this->getBaseLayerSize(), op,
1614 kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001615 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001616 }
1617
1618 SkPath path;
1619 path.addRRect(rrect);
1620 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001621 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001622}
1623
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001624void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001625 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001626 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001627
1628 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1629 SkRect r;
1630 if (path.isRect(&r)) {
1631 this->onClipRect(r, op, edgeStyle);
1632 return;
1633 }
1634 SkRRect rrect;
1635 if (path.isOval(&r)) {
1636 rrect.setOval(r);
1637 this->onClipRRect(rrect, op, edgeStyle);
1638 return;
1639 }
1640 if (path.isRRect(&rrect)) {
1641 this->onClipRRect(rrect, op, edgeStyle);
1642 return;
1643 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001644 }
robertphillips39f05382015-11-24 09:30:12 -08001645
1646 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001647}
1648
1649void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001650#ifdef SK_ENABLE_CLIP_QUICKREJECT
1651 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001652 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001653 return false;
1654 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001655
reed@google.com3b3e8952012-08-16 20:53:31 +00001656 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001657 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001658 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001659
reed687fa1c2015-04-07 08:00:56 -07001660 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001661 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001662 }
1663 }
1664#endif
1665
reed@google.com5c3d1472011-02-22 19:12:23 +00001666 AutoValidateClip avc(this);
1667
reed@android.com8a1c16f2008-12-17 15:59:43 +00001668 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001669 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001670 if (!fAllowSoftClip) {
1671 edgeStyle = kHard_ClipEdgeStyle;
1672 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001673
1674 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001675 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001676
reed@google.comfe701122011-11-08 19:41:23 +00001677 // Check if the transfomation, or the original path itself
1678 // made us empty. Note this can also happen if we contained NaN
1679 // values. computing the bounds detects this, and will set our
1680 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1681 if (devPath.getBounds().isEmpty()) {
1682 // resetting the path will remove any NaN or other wanky values
1683 // that might upset our scan converter.
1684 devPath.reset();
1685 }
1686
reed@google.com5c3d1472011-02-22 19:12:23 +00001687 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001688 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001689
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001690 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001691 bool clipIsAA = getClipStack()->asPath(&devPath);
1692 if (clipIsAA) {
1693 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001694 }
fmalita1a481fe2015-02-04 07:39:34 -08001695
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001696 op = SkRegion::kReplace_Op;
1697 }
1698
reed73e714e2014-09-04 09:02:23 -07001699 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001700}
1701
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001702void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001703 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001704 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001705}
1706
1707void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001708 AutoValidateClip avc(this);
1709
reed@android.com8a1c16f2008-12-17 15:59:43 +00001710 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001711 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001712
reed@google.com5c3d1472011-02-22 19:12:23 +00001713 // todo: signal fClipStack that we have a region, and therefore (I guess)
1714 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001715 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001716
reed1f836ee2014-07-07 07:49:34 -07001717 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001718}
1719
reed@google.com819c9212011-02-23 18:56:55 +00001720#ifdef SK_DEBUG
1721void SkCanvas::validateClip() const {
1722 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001723 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001724 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001725 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001726 return;
1727 }
1728
reed@google.com819c9212011-02-23 18:56:55 +00001729 SkIRect ir;
1730 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001731 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001732
reed687fa1c2015-04-07 08:00:56 -07001733 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001734 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001735 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001736 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001737 case SkClipStack::Element::kRect_Type:
1738 element->getRect().round(&ir);
1739 tmpClip.op(ir, element->getOp());
1740 break;
1741 case SkClipStack::Element::kEmpty_Type:
1742 tmpClip.setEmpty();
1743 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001744 default: {
1745 SkPath path;
1746 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001747 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001748 break;
1749 }
reed@google.com819c9212011-02-23 18:56:55 +00001750 }
1751 }
reed@google.com819c9212011-02-23 18:56:55 +00001752}
1753#endif
1754
reed@google.com90c07ea2012-04-13 13:50:27 +00001755void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001756 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001757 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001758
halcanary96fcdcc2015-08-27 07:41:13 -07001759 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001760 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001761 }
1762}
1763
reed@google.com5c3d1472011-02-22 19:12:23 +00001764///////////////////////////////////////////////////////////////////////////////
1765
reed@google.com754de5f2014-02-24 19:38:20 +00001766bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001767 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001768}
1769
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001770bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001771 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001772}
1773
reed@google.com3b3e8952012-08-16 20:53:31 +00001774bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001775 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001776 return true;
1777
reed1f836ee2014-07-07 07:49:34 -07001778 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001779 return true;
1780 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001781
reed1f836ee2014-07-07 07:49:34 -07001782 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001783 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001784 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001785 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001786 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001787 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001788
reed@android.coma380ae42009-07-21 01:17:02 +00001789 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001790 // TODO: should we use | instead, or compare all 4 at once?
1791 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001792 return true;
1793 }
reed@google.comc0784db2013-12-13 21:16:12 +00001794 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001795 return true;
1796 }
1797 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001798 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001799}
1800
reed@google.com3b3e8952012-08-16 20:53:31 +00001801bool SkCanvas::quickReject(const SkPath& path) const {
1802 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001803}
1804
reed@google.com3b3e8952012-08-16 20:53:31 +00001805bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001806 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001807 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001808 return false;
1809 }
1810
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001811 SkMatrix inverse;
1812 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001813 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001814 if (bounds) {
1815 bounds->setEmpty();
1816 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001817 return false;
1818 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001819
bsalomon49f085d2014-09-05 13:34:00 -07001820 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001821 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001822 // adjust it outwards in case we are antialiasing
1823 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001824
reed@google.com8f4d2302013-12-17 16:44:46 +00001825 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1826 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001827 inverse.mapRect(bounds, r);
1828 }
1829 return true;
1830}
1831
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001832bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001833 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001834 if (clip.isEmpty()) {
1835 if (bounds) {
1836 bounds->setEmpty();
1837 }
1838 return false;
1839 }
1840
bsalomon49f085d2014-09-05 13:34:00 -07001841 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001842 *bounds = clip.getBounds();
1843 }
1844 return true;
1845}
1846
reed@android.com8a1c16f2008-12-17 15:59:43 +00001847const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001848 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001849}
1850
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001851const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001852 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001853}
1854
reed@google.com9c135db2014-03-12 18:28:35 +00001855GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1856 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001857 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001858}
1859
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001860GrContext* SkCanvas::getGrContext() {
1861#if SK_SUPPORT_GPU
1862 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001863 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001864 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001865 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001866 return renderTarget->getContext();
1867 }
1868 }
1869#endif
1870
halcanary96fcdcc2015-08-27 07:41:13 -07001871 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001872
1873}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001874
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001875void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1876 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001877 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001878 if (outer.isEmpty()) {
1879 return;
1880 }
1881 if (inner.isEmpty()) {
1882 this->drawRRect(outer, paint);
1883 return;
1884 }
1885
1886 // We don't have this method (yet), but technically this is what we should
1887 // be able to assert...
1888 // SkASSERT(outer.contains(inner));
1889 //
1890 // For now at least check for containment of bounds
1891 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1892
1893 this->onDrawDRRect(outer, inner, paint);
1894}
1895
reed41af9662015-01-05 07:49:08 -08001896// These need to stop being virtual -- clients need to override the onDraw... versions
1897
1898void SkCanvas::drawPaint(const SkPaint& paint) {
1899 this->onDrawPaint(paint);
1900}
1901
1902void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1903 this->onDrawRect(r, paint);
1904}
1905
1906void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1907 this->onDrawOval(r, paint);
1908}
1909
1910void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1911 this->onDrawRRect(rrect, paint);
1912}
1913
1914void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1915 this->onDrawPoints(mode, count, pts, paint);
1916}
1917
1918void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1919 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1920 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1921 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1922 indices, indexCount, paint);
1923}
1924
1925void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1926 this->onDrawPath(path, paint);
1927}
1928
reeda85d4d02015-05-06 12:56:48 -07001929void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1930 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001931}
1932
reede47829b2015-08-06 10:02:53 -07001933void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1934 const SkPaint* paint, SrcRectConstraint constraint) {
1935 if (dst.isEmpty() || src.isEmpty()) {
1936 return;
1937 }
1938 this->onDrawImageRect(image, &src, dst, paint, constraint);
1939}
reed41af9662015-01-05 07:49:08 -08001940
reed84984ef2015-07-17 07:09:43 -07001941void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1942 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001943 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001944}
1945
reede47829b2015-08-06 10:02:53 -07001946void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1947 SrcRectConstraint constraint) {
1948 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1949 constraint);
1950}
reede47829b2015-08-06 10:02:53 -07001951
reed4c21dc52015-06-25 12:32:03 -07001952void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1953 const SkPaint* paint) {
1954 if (dst.isEmpty()) {
1955 return;
1956 }
1957 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001958 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001959 }
1960 this->onDrawImageNine(image, center, dst, paint);
1961}
1962
reed41af9662015-01-05 07:49:08 -08001963void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001964 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001965 return;
1966 }
reed41af9662015-01-05 07:49:08 -08001967 this->onDrawBitmap(bitmap, dx, dy, paint);
1968}
1969
reede47829b2015-08-06 10:02:53 -07001970void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001971 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001972 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001973 return;
1974 }
reede47829b2015-08-06 10:02:53 -07001975 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001976}
1977
reed84984ef2015-07-17 07:09:43 -07001978void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1979 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001980 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001981}
1982
reede47829b2015-08-06 10:02:53 -07001983void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1984 SrcRectConstraint constraint) {
1985 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1986 constraint);
1987}
reede47829b2015-08-06 10:02:53 -07001988
reed41af9662015-01-05 07:49:08 -08001989void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1990 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001991 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001992 return;
1993 }
reed4c21dc52015-06-25 12:32:03 -07001994 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001995 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001996 }
reed41af9662015-01-05 07:49:08 -08001997 this->onDrawBitmapNine(bitmap, center, dst, paint);
1998}
1999
reed71c3c762015-06-24 10:29:17 -07002000void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2001 const SkColor colors[], int count, SkXfermode::Mode mode,
2002 const SkRect* cull, const SkPaint* paint) {
2003 if (count <= 0) {
2004 return;
2005 }
2006 SkASSERT(atlas);
2007 SkASSERT(xform);
2008 SkASSERT(tex);
2009 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
2010}
2011
reede47829b2015-08-06 10:02:53 -07002012void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2013 const SkPaint* paint, SrcRectConstraint constraint) {
2014 if (src) {
2015 this->drawImageRect(image, *src, dst, paint, constraint);
2016 } else {
2017 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2018 dst, paint, constraint);
2019 }
2020}
2021void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2022 const SkPaint* paint, SrcRectConstraint constraint) {
2023 if (src) {
2024 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2025 } else {
2026 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2027 dst, paint, constraint);
2028 }
2029}
2030
reed@android.com8a1c16f2008-12-17 15:59:43 +00002031//////////////////////////////////////////////////////////////////////////////
2032// These are the virtual drawing methods
2033//////////////////////////////////////////////////////////////////////////////
2034
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002035void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002036 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002037 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2038 }
2039}
2040
reed41af9662015-01-05 07:49:08 -08002041void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002042 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002043 this->internalDrawPaint(paint);
2044}
2045
2046void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002047 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002048
2049 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002050 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002051 }
2052
reed@google.com4e2b3d32011-04-07 14:18:59 +00002053 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002054}
2055
reed41af9662015-01-05 07:49:08 -08002056void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2057 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002058 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002059 if ((long)count <= 0) {
2060 return;
2061 }
2062
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002063 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002064 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002065 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002066 // special-case 2 points (common for drawing a single line)
2067 if (2 == count) {
2068 r.set(pts[0], pts[1]);
2069 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002070 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002071 }
senorblanco87e066e2015-10-28 11:23:36 -07002072 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2073 return;
2074 }
2075 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002076 }
reed@google.coma584aed2012-05-16 14:06:02 +00002077
halcanary96fcdcc2015-08-27 07:41:13 -07002078 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002079
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002080 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002081
reed@android.com8a1c16f2008-12-17 15:59:43 +00002082 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002083 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002084 }
reed@google.com4b226022011-01-11 18:32:13 +00002085
reed@google.com4e2b3d32011-04-07 14:18:59 +00002086 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002087}
2088
reed41af9662015-01-05 07:49:08 -08002089void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002090 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002091 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002092 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002094 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2095 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2096 SkRect tmp(r);
2097 tmp.sort();
2098
senorblanco87e066e2015-10-28 11:23:36 -07002099 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2100 return;
2101 }
2102 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002103 }
reed@google.com4b226022011-01-11 18:32:13 +00002104
reedc83a2972015-07-16 07:40:45 -07002105 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002106
2107 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002108 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002109 }
2110
reed@google.com4e2b3d32011-04-07 14:18:59 +00002111 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002112}
2113
reed41af9662015-01-05 07:49:08 -08002114void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002115 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002116 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002117 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002118 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002119 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2120 return;
2121 }
2122 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002123 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002124
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002125 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002126
2127 while (iter.next()) {
2128 iter.fDevice->drawOval(iter, oval, looper.paint());
2129 }
2130
2131 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002132}
2133
reed41af9662015-01-05 07:49:08 -08002134void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002135 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002136 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002137 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002138 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002139 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2140 return;
2141 }
2142 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002143 }
2144
2145 if (rrect.isRect()) {
2146 // call the non-virtual version
2147 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002148 return;
2149 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002150 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002151 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2152 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002153 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002154
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002155 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002156
2157 while (iter.next()) {
2158 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2159 }
2160
2161 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002162}
2163
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002164void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2165 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002166 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002167 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002168 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002169 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2170 return;
2171 }
2172 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002173 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002174
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002175 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002176
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002177 while (iter.next()) {
2178 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2179 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002180
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002181 LOOPER_END
2182}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002183
reed41af9662015-01-05 07:49:08 -08002184void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002185 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002186 if (!path.isFinite()) {
2187 return;
2188 }
2189
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002190 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002191 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002192 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002193 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002194 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2195 return;
2196 }
2197 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002198 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002199
2200 const SkRect& r = path.getBounds();
2201 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002202 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002203 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002204 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002205 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002206 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002207
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002208 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002209
2210 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002211 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002212 }
2213
reed@google.com4e2b3d32011-04-07 14:18:59 +00002214 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002215}
2216
reed262a71b2015-12-05 13:07:27 -08002217bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
reed262a71b2015-12-05 13:07:27 -08002218 if (!paint.getImageFilter()) {
2219 return false;
2220 }
2221
2222 const SkMatrix& ctm = this->getTotalMatrix();
fmalitac7e211a2016-01-07 10:34:46 -08002223 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
reed262a71b2015-12-05 13:07:27 -08002224 return false;
2225 }
2226
2227 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2228 // Once we can filter and the filter will return a result larger than itself, we should be
2229 // able to remove this constraint.
2230 // skbug.com/4526
2231 //
2232 SkPoint pt;
2233 ctm.mapXY(x, y, &pt);
2234 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2235 return ir.contains(fMCRec->fRasterClip.getBounds());
2236}
2237
reeda85d4d02015-05-06 12:56:48 -07002238void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002239 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002240 SkRect bounds = SkRect::MakeXYWH(x, y,
2241 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002242 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002243 SkRect tmp = bounds;
2244 if (paint) {
2245 paint->computeFastBounds(tmp, &tmp);
2246 }
2247 if (this->quickReject(tmp)) {
2248 return;
2249 }
reeda85d4d02015-05-06 12:56:48 -07002250 }
2251
2252 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002253 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002254 paint = lazy.init();
2255 }
reed262a71b2015-12-05 13:07:27 -08002256
2257 const bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2258 *paint);
2259 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2260
reeda85d4d02015-05-06 12:56:48 -07002261 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002262 const SkPaint& pnt = looper.paint();
2263 if (drawAsSprite && pnt.getImageFilter()) {
2264 SkBitmap bitmap;
2265 if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2266 SkPoint pt;
2267 iter.fMatrix->mapXY(x, y, &pt);
2268 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2269 SkScalarRoundToInt(pt.fX),
2270 SkScalarRoundToInt(pt.fY), pnt);
2271 }
2272 } else {
2273 iter.fDevice->drawImage(iter, image, x, y, pnt);
2274 }
reeda85d4d02015-05-06 12:56:48 -07002275 }
2276
2277 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002278}
2279
reed41af9662015-01-05 07:49:08 -08002280void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002281 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002282 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
halcanary96fcdcc2015-08-27 07:41:13 -07002283 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002284 SkRect storage = dst;
senorblanco87e066e2015-10-28 11:23:36 -07002285 if (paint) {
2286 paint->computeFastBounds(dst, &storage);
2287 }
2288 if (this->quickReject(storage)) {
2289 return;
2290 }
reeda85d4d02015-05-06 12:56:48 -07002291 }
2292 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002293 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002294 paint = lazy.init();
2295 }
2296
senorblancoc41e7e12015-12-07 12:51:30 -08002297 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002298 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002299
2300 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002301 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002302 }
2303
2304 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002305}
2306
reed41af9662015-01-05 07:49:08 -08002307void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002308 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002309 SkDEBUGCODE(bitmap.validate();)
2310
reed33366972015-10-08 09:22:02 -07002311 if (bitmap.drawsNothing()) {
2312 return;
2313 }
2314
2315 SkLazyPaint lazy;
2316 if (nullptr == paint) {
2317 paint = lazy.init();
2318 }
2319
2320 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2321
2322 SkRect storage;
2323 const SkRect* bounds = nullptr;
2324 if (paint->canComputeFastBounds()) {
2325 bitmap.getBounds(&storage);
2326 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002327 SkRect tmp = storage;
2328 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2329 return;
2330 }
2331 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002332 }
reed@google.com4b226022011-01-11 18:32:13 +00002333
reed262a71b2015-12-05 13:07:27 -08002334 const bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(),
2335 bitmap.height(), *paint);
2336 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
reed33366972015-10-08 09:22:02 -07002337
2338 while (iter.next()) {
reed262a71b2015-12-05 13:07:27 -08002339 const SkPaint& pnt = looper.paint();
2340 if (drawAsSprite && pnt.getImageFilter()) {
2341 SkPoint pt;
2342 iter.fMatrix->mapXY(x, y, &pt);
2343 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2344 SkScalarRoundToInt(pt.fX),
2345 SkScalarRoundToInt(pt.fY), pnt);
2346 } else {
2347 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2348 }
reed33366972015-10-08 09:22:02 -07002349 }
reed262a71b2015-12-05 13:07:27 -08002350
reed33366972015-10-08 09:22:02 -07002351 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002352}
2353
reed@google.com9987ec32011-09-07 11:57:52 +00002354// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002355void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002356 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002357 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002358 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002359 return;
2360 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002361
halcanary96fcdcc2015-08-27 07:41:13 -07002362 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002363 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002364 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2365 return;
2366 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002367 }
reed@google.com3d608122011-11-21 15:16:16 +00002368
reed@google.com33535f32012-09-25 15:37:50 +00002369 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002370 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002371 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002372 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002373
senorblancoc41e7e12015-12-07 12:51:30 -08002374 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
reedc83a2972015-07-16 07:40:45 -07002375 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002376
reed@google.com33535f32012-09-25 15:37:50 +00002377 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002378 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002379 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002380
reed@google.com33535f32012-09-25 15:37:50 +00002381 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002382}
2383
reed41af9662015-01-05 07:49:08 -08002384void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002385 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002386 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002387 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002388 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002389}
2390
reed4c21dc52015-06-25 12:32:03 -07002391void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2392 const SkPaint* paint) {
2393 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2394
halcanary96fcdcc2015-08-27 07:41:13 -07002395 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002396 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002397 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2398 return;
2399 }
reed@google.com3d608122011-11-21 15:16:16 +00002400 }
reed4c21dc52015-06-25 12:32:03 -07002401
2402 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002403 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002404 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002405 }
reed4c21dc52015-06-25 12:32:03 -07002406
senorblancoc41e7e12015-12-07 12:51:30 -08002407 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002408
2409 while (iter.next()) {
2410 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002411 }
reed4c21dc52015-06-25 12:32:03 -07002412
2413 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002414}
2415
reed41af9662015-01-05 07:49:08 -08002416void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2417 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002418 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002419 SkDEBUGCODE(bitmap.validate();)
2420
halcanary96fcdcc2015-08-27 07:41:13 -07002421 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblancoc41e7e12015-12-07 12:51:30 -08002422 SkRect storage;
senorblanco87e066e2015-10-28 11:23:36 -07002423 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2424 return;
2425 }
reed4c21dc52015-06-25 12:32:03 -07002426 }
2427
2428 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002429 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002430 paint = lazy.init();
2431 }
2432
senorblancoc41e7e12015-12-07 12:51:30 -08002433 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
reed4c21dc52015-06-25 12:32:03 -07002434
2435 while (iter.next()) {
2436 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2437 }
2438
2439 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002440}
2441
reed@google.comf67e4cf2011-03-15 20:56:58 +00002442class SkDeviceFilteredPaint {
2443public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002444 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002445 uint32_t filteredFlags = device->filterTextFlags(paint);
2446 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002447 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002448 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002449 fPaint = newPaint;
2450 } else {
2451 fPaint = &paint;
2452 }
2453 }
2454
reed@google.comf67e4cf2011-03-15 20:56:58 +00002455 const SkPaint& paint() const { return *fPaint; }
2456
2457private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002458 const SkPaint* fPaint;
2459 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002460};
2461
bungeman@google.com52c748b2011-08-22 21:30:43 +00002462void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2463 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002464 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002465 draw.fDevice->drawRect(draw, r, paint);
2466 } else {
2467 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002468 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002469 draw.fDevice->drawRect(draw, r, p);
2470 }
2471}
2472
2473void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2474 const char text[], size_t byteLength,
2475 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002476 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002477
2478 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002479 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002480 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002481 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002482 return;
2483 }
2484
2485 SkScalar width = 0;
2486 SkPoint start;
2487
2488 start.set(0, 0); // to avoid warning
2489 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2490 SkPaint::kStrikeThruText_Flag)) {
2491 width = paint.measureText(text, byteLength);
2492
2493 SkScalar offsetX = 0;
2494 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2495 offsetX = SkScalarHalf(width);
2496 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2497 offsetX = width;
2498 }
2499 start.set(x - offsetX, y);
2500 }
2501
2502 if (0 == width) {
2503 return;
2504 }
2505
2506 uint32_t flags = paint.getFlags();
2507
2508 if (flags & (SkPaint::kUnderlineText_Flag |
2509 SkPaint::kStrikeThruText_Flag)) {
2510 SkScalar textSize = paint.getTextSize();
2511 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2512 SkRect r;
2513
2514 r.fLeft = start.fX;
2515 r.fRight = start.fX + width;
2516
2517 if (flags & SkPaint::kUnderlineText_Flag) {
2518 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2519 start.fY);
2520 r.fTop = offset;
2521 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002522 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002523 }
2524 if (flags & SkPaint::kStrikeThruText_Flag) {
2525 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2526 start.fY);
2527 r.fTop = offset;
2528 r.fBottom = offset + height;
caryclarkfb562182015-12-21 08:35:51 -08002529 DrawRect(draw, paint, r, 1);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002530 }
2531 }
2532}
2533
reed@google.come0d9ce82014-04-23 04:00:17 +00002534void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2535 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002536 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002537
2538 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002539 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002540 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002541 DrawTextDecorations(iter, dfp.paint(),
2542 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002543 }
2544
reed@google.com4e2b3d32011-04-07 14:18:59 +00002545 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002546}
2547
reed@google.come0d9ce82014-04-23 04:00:17 +00002548void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2549 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002550 SkPoint textOffset = SkPoint::Make(0, 0);
2551
halcanary96fcdcc2015-08-27 07:41:13 -07002552 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002553
reed@android.com8a1c16f2008-12-17 15:59:43 +00002554 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002555 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002556 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002557 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002558 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002559
reed@google.com4e2b3d32011-04-07 14:18:59 +00002560 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002561}
2562
reed@google.come0d9ce82014-04-23 04:00:17 +00002563void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2564 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002565
2566 SkPoint textOffset = SkPoint::Make(0, constY);
2567
halcanary96fcdcc2015-08-27 07:41:13 -07002568 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002569
reed@android.com8a1c16f2008-12-17 15:59:43 +00002570 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002571 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002572 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002573 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002574 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002575
reed@google.com4e2b3d32011-04-07 14:18:59 +00002576 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002577}
2578
reed@google.come0d9ce82014-04-23 04:00:17 +00002579void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2580 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002581 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002582
reed@android.com8a1c16f2008-12-17 15:59:43 +00002583 while (iter.next()) {
2584 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002585 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002586 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002587
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002588 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002589}
2590
fmalita00d5c2c2014-08-21 08:53:26 -07002591void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2592 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002593
fmalita85d5eb92015-03-04 11:20:12 -08002594 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002595 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002596 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002597 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002598 SkRect tmp;
2599 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2600 return;
2601 }
2602 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002603 }
2604
fmalita024f9962015-03-03 19:08:17 -08002605 // We cannot filter in the looper as we normally do, because the paint is
2606 // incomplete at this point (text-related attributes are embedded within blob run paints).
2607 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002608 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002609
fmalita85d5eb92015-03-04 11:20:12 -08002610 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002611
fmalitaaa1b9122014-08-28 14:32:24 -07002612 while (iter.next()) {
2613 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002614 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002615 }
2616
fmalitaaa1b9122014-08-28 14:32:24 -07002617 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002618
2619 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002620}
2621
reed@google.come0d9ce82014-04-23 04:00:17 +00002622// These will become non-virtual, so they always call the (virtual) onDraw... method
2623void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2624 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002625 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002626 this->onDrawText(text, byteLength, x, y, paint);
2627}
2628void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2629 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002630 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002631 this->onDrawPosText(text, byteLength, pos, paint);
2632}
2633void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2634 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002635 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002636 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2637}
2638void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2639 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002640 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002641 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2642}
fmalita00d5c2c2014-08-21 08:53:26 -07002643void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2644 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002645 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002646 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002647 this->onDrawTextBlob(blob, x, y, paint);
2648 }
2649}
reed@google.come0d9ce82014-04-23 04:00:17 +00002650
reed41af9662015-01-05 07:49:08 -08002651void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2652 const SkPoint verts[], const SkPoint texs[],
2653 const SkColor colors[], SkXfermode* xmode,
2654 const uint16_t indices[], int indexCount,
2655 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002656 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002657 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002658
reed@android.com8a1c16f2008-12-17 15:59:43 +00002659 while (iter.next()) {
2660 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002661 colors, xmode, indices, indexCount,
2662 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002663 }
reed@google.com4b226022011-01-11 18:32:13 +00002664
reed@google.com4e2b3d32011-04-07 14:18:59 +00002665 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002666}
2667
dandovb3c9d1c2014-08-12 08:34:29 -07002668void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2669 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002670 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002671 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002672 return;
2673 }
mtklein6cfa73a2014-08-13 13:33:49 -07002674
dandovecfff212014-08-04 10:02:00 -07002675 // Since a patch is always within the convex hull of the control points, we discard it when its
2676 // bounding rectangle is completely outside the current clip.
2677 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002678 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002679 if (this->quickReject(bounds)) {
2680 return;
2681 }
mtklein6cfa73a2014-08-13 13:33:49 -07002682
dandovb3c9d1c2014-08-12 08:34:29 -07002683 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2684}
2685
2686void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2687 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2688
halcanary96fcdcc2015-08-27 07:41:13 -07002689 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002690
dandovecfff212014-08-04 10:02:00 -07002691 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002692 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002693 }
mtklein6cfa73a2014-08-13 13:33:49 -07002694
dandovecfff212014-08-04 10:02:00 -07002695 LOOPER_END
2696}
2697
reeda8db7282015-07-07 10:22:31 -07002698void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2699 if (dr) {
2700 if (x || y) {
2701 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2702 this->onDrawDrawable(dr, &matrix);
2703 } else {
halcanary96fcdcc2015-08-27 07:41:13 -07002704 this->onDrawDrawable(dr, nullptr);
reeda8db7282015-07-07 10:22:31 -07002705 }
reed6a070dc2014-11-11 19:36:09 -08002706 }
2707}
2708
reeda8db7282015-07-07 10:22:31 -07002709void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2710 if (dr) {
2711 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002712 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002713 }
2714 this->onDrawDrawable(dr, matrix);
2715 }
2716}
2717
2718void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2719 SkRect bounds = dr->getBounds();
2720 if (matrix) {
2721 matrix->mapRect(&bounds);
2722 }
2723 if (this->quickReject(bounds)) {
2724 return;
2725 }
2726 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002727}
2728
reed71c3c762015-06-24 10:29:17 -07002729void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2730 const SkColor colors[], int count, SkXfermode::Mode mode,
2731 const SkRect* cull, const SkPaint* paint) {
2732 if (cull && this->quickReject(*cull)) {
2733 return;
2734 }
2735
2736 SkPaint pnt;
2737 if (paint) {
2738 pnt = *paint;
2739 }
2740
halcanary96fcdcc2015-08-27 07:41:13 -07002741 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002742 while (iter.next()) {
2743 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2744 }
2745 LOOPER_END
2746}
2747
reed@android.com8a1c16f2008-12-17 15:59:43 +00002748//////////////////////////////////////////////////////////////////////////////
2749// These methods are NOT virtual, and therefore must call back into virtual
2750// methods, rather than actually drawing themselves.
2751//////////////////////////////////////////////////////////////////////////////
2752
2753void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002754 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002755 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002756 SkPaint paint;
2757
2758 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002759 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002760 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002761 }
2762 this->drawPaint(paint);
2763}
2764
reed@android.com845fdac2009-06-23 03:01:32 +00002765void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002766 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002767 SkPaint paint;
2768
2769 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002770 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002771 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002772 }
2773 this->drawPaint(paint);
2774}
2775
2776void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002777 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002778 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002779
reed@android.com8a1c16f2008-12-17 15:59:43 +00002780 pt.set(x, y);
2781 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2782}
2783
2784void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002785 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786 SkPoint pt;
2787 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002788
reed@android.com8a1c16f2008-12-17 15:59:43 +00002789 pt.set(x, y);
2790 paint.setColor(color);
2791 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2792}
2793
2794void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2795 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002796 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002797 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002798
reed@android.com8a1c16f2008-12-17 15:59:43 +00002799 pts[0].set(x0, y0);
2800 pts[1].set(x1, y1);
2801 this->drawPoints(kLines_PointMode, 2, pts, paint);
2802}
2803
2804void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2805 SkScalar right, SkScalar bottom,
2806 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002807 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002808 SkRect r;
2809
2810 r.set(left, top, right, bottom);
2811 this->drawRect(r, paint);
2812}
2813
2814void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2815 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002816 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002817 if (radius < 0) {
2818 radius = 0;
2819 }
2820
2821 SkRect r;
2822 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002823 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002824}
2825
2826void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2827 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002828 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002829 if (rx > 0 && ry > 0) {
2830 if (paint.canComputeFastBounds()) {
2831 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002832 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002833 return;
2834 }
2835 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002836 SkRRect rrect;
2837 rrect.setRectXY(r, rx, ry);
2838 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002839 } else {
2840 this->drawRect(r, paint);
2841 }
2842}
2843
reed@android.com8a1c16f2008-12-17 15:59:43 +00002844void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2845 SkScalar sweepAngle, bool useCenter,
2846 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002847 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002848 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2849 this->drawOval(oval, paint);
2850 } else {
2851 SkPath path;
2852 if (useCenter) {
2853 path.moveTo(oval.centerX(), oval.centerY());
2854 }
2855 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2856 if (useCenter) {
2857 path.close();
2858 }
2859 this->drawPath(path, paint);
2860 }
2861}
2862
2863void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2864 const SkPath& path, SkScalar hOffset,
2865 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002866 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002867 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002868
reed@android.com8a1c16f2008-12-17 15:59:43 +00002869 matrix.setTranslate(hOffset, vOffset);
2870 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2871}
2872
reed@android.comf76bacf2009-05-13 14:00:33 +00002873///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002874
2875/**
2876 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2877 * against the playback cost of recursing into the subpicture to get at its actual ops.
2878 *
2879 * For now we pick a conservatively small value, though measurement (and other heuristics like
2880 * the type of ops contained) may justify changing this value.
2881 */
2882#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002883
reedd5fa1a42014-08-09 11:08:05 -07002884void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002885 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002886 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002887 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002888 matrix = nullptr;
reedd5fa1a42014-08-09 11:08:05 -07002889 }
reed1c2c4412015-04-30 13:09:24 -07002890 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2891 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2892 picture->playback(this);
2893 } else {
2894 this->onDrawPicture(picture, matrix, paint);
2895 }
reedd5fa1a42014-08-09 11:08:05 -07002896 }
2897}
robertphillips9b14f262014-06-04 05:40:44 -07002898
reedd5fa1a42014-08-09 11:08:05 -07002899void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2900 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002901 if (!paint || paint->canComputeFastBounds()) {
2902 SkRect bounds = picture->cullRect();
2903 if (paint) {
2904 paint->computeFastBounds(bounds, &bounds);
2905 }
2906 if (matrix) {
2907 matrix->mapRect(&bounds);
2908 }
2909 if (this->quickReject(bounds)) {
2910 return;
2911 }
2912 }
2913
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002914 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002915 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002916 // Canvas has to first give the device the opportunity to render
2917 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002918 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002919 return; // the device has rendered the entire picture
2920 }
2921 }
2922
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002923 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002924 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002925}
2926
reed@android.com8a1c16f2008-12-17 15:59:43 +00002927///////////////////////////////////////////////////////////////////////////////
2928///////////////////////////////////////////////////////////////////////////////
2929
2930SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002931 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002932
2933 SkASSERT(canvas);
2934
2935 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2936 fDone = !fImpl->next();
2937}
2938
2939SkCanvas::LayerIter::~LayerIter() {
2940 fImpl->~SkDrawIter();
2941}
2942
2943void SkCanvas::LayerIter::next() {
2944 fDone = !fImpl->next();
2945}
2946
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002947SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002948 return fImpl->getDevice();
2949}
2950
2951const SkMatrix& SkCanvas::LayerIter::matrix() const {
2952 return fImpl->getMatrix();
2953}
2954
2955const SkPaint& SkCanvas::LayerIter::paint() const {
2956 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002957 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002958 paint = &fDefaultPaint;
2959 }
2960 return *paint;
2961}
2962
2963const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2964int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2965int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002966
2967///////////////////////////////////////////////////////////////////////////////
2968
fmalitac3b589a2014-06-05 12:40:07 -07002969SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002970
2971///////////////////////////////////////////////////////////////////////////////
2972
2973static bool supported_for_raster_canvas(const SkImageInfo& info) {
2974 switch (info.alphaType()) {
2975 case kPremul_SkAlphaType:
2976 case kOpaque_SkAlphaType:
2977 break;
2978 default:
2979 return false;
2980 }
2981
2982 switch (info.colorType()) {
2983 case kAlpha_8_SkColorType:
2984 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002985 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002986 break;
2987 default:
2988 return false;
2989 }
2990
2991 return true;
2992}
2993
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002994SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2995 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002996 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002997 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002998
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002999 SkBitmap bitmap;
3000 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003001 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003002 }
halcanary385fe4d2015-08-26 13:07:48 -07003003 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003004}
reedd5fa1a42014-08-09 11:08:05 -07003005
3006///////////////////////////////////////////////////////////////////////////////
3007
3008SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003009 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003010 : fCanvas(canvas)
3011 , fSaveCount(canvas->getSaveCount())
3012{
bsalomon49f085d2014-09-05 13:34:00 -07003013 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003014 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003015 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003016 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003017 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003018 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003019 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003020 canvas->save();
3021 }
mtklein6cfa73a2014-08-13 13:33:49 -07003022
bsalomon49f085d2014-09-05 13:34:00 -07003023 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003024 canvas->concat(*matrix);
3025 }
3026}
3027
3028SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3029 fCanvas->restoreToCount(fSaveCount);
3030}