blob: 1b32236ebc96c9333a90ada91e72c816d3d6edfb [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"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000020#include "SkMetaData.h"
reed4c21dc52015-06-25 12:32:03 -070021#include "SkNinePatchIter.h"
reedc83a2972015-07-16 07:40:45 -070022#include "SkPaintPriv.h"
dandovb3c9d1c2014-08-12 08:34:29 -070023#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000024#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000025#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080026#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000027#include "SkRRect.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000028#include "SkSmallAllocator.h"
reed@google.com97af1a62012-08-28 12:19:02 +000029#include "SkSurface_Base.h"
fmalita7ba7aa72014-08-29 09:46:36 -070030#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000031#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000032#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080033#include "SkTraceEvent.h"
bungemand3ebb482015-08-05 13:57:49 -070034
35#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000036
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000037#if SK_SUPPORT_GPU
38#include "GrRenderTarget.h"
39#endif
40
senorblanco87e066e2015-10-28 11:23:36 -070041#ifndef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
42#define SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
43#endif
44
reedc83a2972015-07-16 07:40:45 -070045/*
46 * Return true if the drawing this rect would hit every pixels in the canvas.
47 *
48 * Returns false if
49 * - rect does not contain the canvas' bounds
50 * - paint is not fill
51 * - paint would blur or otherwise change the coverage of the rect
52 */
53bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
54 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070055 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
56 (int)kNone_ShaderOverrideOpacity,
57 "need_matching_enums0");
58 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
59 (int)kOpaque_ShaderOverrideOpacity,
60 "need_matching_enums1");
61 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
62 (int)kNotOpaque_ShaderOverrideOpacity,
63 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070064
65 const SkISize size = this->getBaseLayerSize();
66 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
67 if (!this->getClipStack()->quickContains(bounds)) {
68 return false;
69 }
70
71 if (rect) {
72 if (!this->getTotalMatrix().rectStaysRect()) {
73 return false; // conservative
74 }
75
76 SkRect devRect;
77 this->getTotalMatrix().mapRect(&devRect, *rect);
fmalita8c0144c2015-07-22 05:56:16 -070078 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070079 return false;
80 }
81 }
82
83 if (paint) {
84 SkPaint::Style paintStyle = paint->getStyle();
85 if (!(paintStyle == SkPaint::kFill_Style ||
86 paintStyle == SkPaint::kStrokeAndFill_Style)) {
87 return false;
88 }
89 if (paint->getMaskFilter() || paint->getLooper()
90 || paint->getPathEffect() || paint->getImageFilter()) {
91 return false; // conservative
92 }
93 }
94 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
95}
96
97///////////////////////////////////////////////////////////////////////////////////////////////////
98
reedd990e2f2014-12-22 11:58:30 -080099static bool gIgnoreSaveLayerBounds;
100void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
101 gIgnoreSaveLayerBounds = ignore;
102}
103bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
104 return gIgnoreSaveLayerBounds;
105}
106
reed0acf1b42014-12-22 16:12:38 -0800107static bool gTreatSpriteAsBitmap;
108void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
109 gTreatSpriteAsBitmap = spriteAsBitmap;
110}
111bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
112 return gTreatSpriteAsBitmap;
113}
114
reed@google.comda17f752012-08-16 18:27:05 +0000115// experimental for faster tiled drawing...
116//#define SK_ENABLE_CLIP_QUICKREJECT
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +0000117
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118//#define SK_TRACE_SAVERESTORE
119
120#ifdef SK_TRACE_SAVERESTORE
121 static int gLayerCounter;
122 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
123 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
124
125 static int gRecCounter;
126 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
127 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
128
129 static int gCanvasCounter;
130 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
131 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
132#else
133 #define inc_layer()
134 #define dec_layer()
135 #define inc_rec()
136 #define dec_rec()
137 #define inc_canvas()
138 #define dec_canvas()
139#endif
140
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000141typedef SkTLazy<SkPaint> SkLazyPaint;
142
reedc83a2972015-07-16 07:40:45 -0700143void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000144 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700145 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
146 ? SkSurface::kDiscard_ContentChangeMode
147 : SkSurface::kRetain_ContentChangeMode);
148 }
149}
150
151void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
152 ShaderOverrideOpacity overrideOpacity) {
153 if (fSurfaceBase) {
154 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
155 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
156 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
157 // and therefore we don't care which mode we're in.
158 //
159 if (fSurfaceBase->outstandingImageSnapshot()) {
160 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
161 mode = SkSurface::kDiscard_ContentChangeMode;
162 }
163 }
164 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000165 }
166}
167
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169
reed4a8126e2014-09-22 07:29:03 -0700170static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
171 const uint32_t propFlags = props.flags();
172 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
173 flags &= ~SkPaint::kDither_Flag;
174 }
175 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
176 flags &= ~SkPaint::kAntiAlias_Flag;
177 }
178 return flags;
179}
180
181///////////////////////////////////////////////////////////////////////////////
182
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000183/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 The clip/matrix/proc are fields that reflect the top of the save/restore
185 stack. Whenever the canvas changes, it marks a dirty flag, and then before
186 these are used (assuming we're not on a layer) we rebuild these cache
187 values: they reflect the top of the save stack, but translated and clipped
188 by the device's XY offset and bitmap-bounds.
189*/
190struct DeviceCM {
191 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000192 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000193 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000194 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700195 const SkMatrix* fMatrix;
196 SkMatrix fMatrixStorage;
197 const bool fDeviceIsBitmapDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198
reed96e657d2015-03-10 17:30:07 -0700199 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed86a17e72015-05-14 12:25:22 -0700200 bool conservativeRasterClip, bool deviceIsBitmapDevice)
halcanary96fcdcc2015-08-27 07:41:13 -0700201 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700202 , fClip(conservativeRasterClip)
reed61f501f2015-04-29 08:34:00 -0700203 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700204 {
halcanary96fcdcc2015-08-27 07:41:13 -0700205 if (nullptr != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000207 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 }
reed@google.com4b226022011-01-11 18:32:13 +0000209 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700210 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000211 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000213 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700214 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000215 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 fDevice->unref();
217 }
halcanary385fe4d2015-08-26 13:07:48 -0700218 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000219 }
reed@google.com4b226022011-01-11 18:32:13 +0000220
mtkleinfeaadee2015-04-08 11:25:48 -0700221 void reset(const SkIRect& bounds) {
222 SkASSERT(!fPaint);
223 SkASSERT(!fNext);
224 SkASSERT(fDevice);
225 fClip.setRect(bounds);
226 }
227
reed@google.com045e62d2011-10-24 12:19:46 +0000228 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
229 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000230 int x = fDevice->getOrigin().x();
231 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 int width = fDevice->width();
233 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000234
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235 if ((x | y) == 0) {
236 fMatrix = &totalMatrix;
237 fClip = totalClip;
238 } else {
239 fMatrixStorage = totalMatrix;
240 fMatrixStorage.postTranslate(SkIntToScalar(-x),
241 SkIntToScalar(-y));
242 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000243
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 totalClip.translate(-x, -y, &fClip);
245 }
246
reed@google.com045e62d2011-10-24 12:19:46 +0000247 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248
249 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000250
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000252 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 SkRegion::kDifference_Op);
254 }
reed@google.com4b226022011-01-11 18:32:13 +0000255
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000256 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
257
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258#ifdef SK_DEBUG
259 if (!fClip.isEmpty()) {
260 SkIRect deviceR;
261 deviceR.set(0, 0, width, height);
262 SkASSERT(deviceR.contains(fClip.getBounds()));
263 }
264#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000265 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266};
267
268/* This is the record we keep for each save/restore level in the stack.
269 Since a level optionally copies the matrix and/or stack, we have pointers
270 for these fields. If the value is copied for this level, the copy is
271 stored in the ...Storage field, and the pointer points to that. If the
272 value is not copied for this level, we ignore ...Storage, and just point
273 at the corresponding value in the previous level in the stack.
274*/
275class SkCanvas::MCRec {
276public:
reed1f836ee2014-07-07 07:49:34 -0700277 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700278 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 /* If there are any layers in the stack, this points to the top-most
280 one that is at or below this level in the stack (so we know what
281 bitmap/device to draw into from this level. This value is NOT
282 reference counted, since the real owner is either our fLayer field,
283 or a previous one in a lower level.)
284 */
reed2ff1fce2014-12-11 07:07:37 -0800285 DeviceCM* fTopLayer;
286 SkRasterClip fRasterClip;
287 SkMatrix fMatrix;
288 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289
reedd9544982014-09-09 18:46:22 -0700290 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700291 fFilter = nullptr;
292 fLayer = nullptr;
293 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800294 fMatrix.reset();
295 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700296
reedd9544982014-09-09 18:46:22 -0700297 // don't bother initializing fNext
298 inc_rec();
299 }
reed2ff1fce2014-12-11 07:07:37 -0800300 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700301 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700302 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700303 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800304 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700305
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306 // don't bother initializing fNext
307 inc_rec();
308 }
309 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000310 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700311 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000312 dec_rec();
313 }
mtkleinfeaadee2015-04-08 11:25:48 -0700314
315 void reset(const SkIRect& bounds) {
316 SkASSERT(fLayer);
317 SkASSERT(fDeferredSaveCount == 0);
318
319 fMatrix.reset();
320 fRasterClip.setRect(bounds);
321 fLayer->reset(bounds);
322 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323};
324
325class SkDrawIter : public SkDraw {
326public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000327 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000328 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000329 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330 canvas->updateDeviceCMCache();
331
reed687fa1c2015-04-07 08:00:56 -0700332 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000334 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 }
reed@google.com4b226022011-01-11 18:32:13 +0000336
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 bool next() {
338 // skip over recs with empty clips
339 if (fSkipEmptyClips) {
340 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
341 fCurrLayer = fCurrLayer->fNext;
342 }
343 }
344
reed@google.comf68c5e22012-02-24 16:38:58 +0000345 const DeviceCM* rec = fCurrLayer;
346 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347
348 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000349 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
350 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700352 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700353 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700354 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000356 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357
358 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700359 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000360
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 return true;
362 }
363 return false;
364 }
reed@google.com4b226022011-01-11 18:32:13 +0000365
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000366 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000367 int getX() const { return fDevice->getOrigin().x(); }
368 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 const SkMatrix& getMatrix() const { return *fMatrix; }
370 const SkRegion& getClip() const { return *fClip; }
371 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000372
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373private:
374 SkCanvas* fCanvas;
375 const DeviceCM* fCurrLayer;
376 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377 SkBool8 fSkipEmptyClips;
378
379 typedef SkDraw INHERITED;
380};
381
382/////////////////////////////////////////////////////////////////////////////
383
reeddbc3cef2015-04-29 12:18:57 -0700384static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
385 return lazy->isValid() ? lazy->get() : lazy->set(orig);
386}
387
388/**
389 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700390 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700391 */
392static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700393 SkImageFilter* imgf = paint.getImageFilter();
394 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700395 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700396 }
397
398 SkColorFilter* imgCF;
399 if (!imgf->asAColorFilter(&imgCF)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700400 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700401 }
402
403 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700404 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700405 // there is no existing paint colorfilter, so we can just return the imagefilter's
406 return imgCF;
407 }
408
409 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
410 // and we need to combine them into a single colorfilter.
411 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
412 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
reeddbc3cef2015-04-29 12:18:57 -0700413}
414
senorblanco87e066e2015-10-28 11:23:36 -0700415/**
416 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
417 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
418 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
419 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
420 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
421 * conservative "effective" bounds based on the settings in the paint... with one exception. This
422 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
423 * deliberately ignored.
424 */
425static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
426 const SkRect& rawBounds,
427 SkRect* storage) {
428 SkPaint tmpUnfiltered(paint);
429 tmpUnfiltered.setImageFilter(nullptr);
430 if (tmpUnfiltered.canComputeFastBounds()) {
431 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
432 } else {
433 return rawBounds;
434 }
435}
436
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437class AutoDrawLooper {
438public:
senorblanco87e066e2015-10-28 11:23:36 -0700439 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
440 // paint. It's used to determine the size of the offscreen layer for filters.
441 // If null, the clip will be used instead.
reed4a8126e2014-09-22 07:29:03 -0700442 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000443 bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700444 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000445 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700447 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000448 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700449 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000450 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000451
reeddbc3cef2015-04-29 12:18:57 -0700452 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
453 if (simplifiedCF) {
454 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
455 paint->setColorFilter(simplifiedCF)->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700456 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700457 fPaint = paint;
458 }
459
460 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700461 /**
462 * We implement ImageFilters for a given draw by creating a layer, then applying the
463 * imagefilter to the pixels of that layer (its backing surface/image), and then
464 * we call restore() to xfer that layer to the main canvas.
465 *
466 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
467 * 2. Generate the src pixels:
468 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
469 * return (fPaint). We then draw the primitive (using srcover) into a cleared
470 * buffer/surface.
471 * 3. Restore the layer created in #1
472 * The imagefilter is passed the buffer/surface from the layer (now filled with the
473 * src pixels of the primitive). It returns a new "filtered" buffer, which we
474 * draw onto the previous layer using the xfermode from the original paint.
475 */
reed@google.com8926b162012-03-23 15:36:36 +0000476 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700477 tmp.setImageFilter(fPaint->getImageFilter());
478 tmp.setXfermode(fPaint->getXfermode());
senorblanco87e066e2015-10-28 11:23:36 -0700479#ifndef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
480 SkRect storage;
481 if (rawBounds) {
482 // Make rawBounds include all paint outsets except for those due to image filters.
483 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
484 }
485#endif
486 (void)canvas->internalSaveLayer(rawBounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
reed76033be2015-03-14 10:54:31 -0700487 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700488 fTempLayerForImageFilter = true;
489 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000490 }
491
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000492 if (SkDrawLooper* looper = paint.getLooper()) {
493 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
494 looper->contextSize());
495 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000496 fIsSimple = false;
497 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700498 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000499 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700500 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000501 }
piotaixrb5fae932014-09-24 13:03:30 -0700502
reed4a8126e2014-09-22 07:29:03 -0700503 uint32_t oldFlags = paint.getFlags();
504 fNewPaintFlags = filter_paint_flags(props, oldFlags);
505 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700506 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700507 paint->setFlags(fNewPaintFlags);
508 fPaint = paint;
509 // if we're not simple, doNext() will take care of calling setFlags()
510 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000511 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000512
reed@android.com8a1c16f2008-12-17 15:59:43 +0000513 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700514 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000515 fCanvas->internalRestore();
516 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000517 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000518 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000519
reed@google.com4e2b3d32011-04-07 14:18:59 +0000520 const SkPaint& paint() const {
521 SkASSERT(fPaint);
522 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000524
reed@google.com129ec222012-05-15 13:24:09 +0000525 bool next(SkDrawFilter::Type drawType) {
526 if (fDone) {
527 return false;
528 } else if (fIsSimple) {
529 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000530 return !fPaint->nothingToDraw();
531 } else {
532 return this->doNext(drawType);
533 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000534 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000535
reed@android.com8a1c16f2008-12-17 15:59:43 +0000536private:
reeddbc3cef2015-04-29 12:18:57 -0700537 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
538 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000539 SkCanvas* fCanvas;
540 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000541 SkDrawFilter* fFilter;
542 const SkPaint* fPaint;
543 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700544 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700545 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000546 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000547 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000548 SkDrawLooper::Context* fLooperContext;
549 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000550
551 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552};
553
reed@google.com129ec222012-05-15 13:24:09 +0000554bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700555 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000556 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700557 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000558
reeddbc3cef2015-04-29 12:18:57 -0700559 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
560 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700561 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000562
reed5c476fb2015-04-20 08:04:21 -0700563 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700564 paint->setImageFilter(nullptr);
565 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000566 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000567
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000568 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000569 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000570 return false;
571 }
572 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000573 if (!fFilter->filter(paint, drawType)) {
574 fDone = true;
575 return false;
576 }
halcanary96fcdcc2015-08-27 07:41:13 -0700577 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000578 // no looper means we only draw once
579 fDone = true;
580 }
581 }
582 fPaint = paint;
583
584 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000585 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000586 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000587 }
588
589 // call this after any possible paint modifiers
590 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700591 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000592 return false;
593 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000594 return true;
595}
596
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597////////// macros to place around the internal draw calls //////////////////
598
reed@google.com8926b162012-03-23 15:36:36 +0000599#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000600 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700601 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000602 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000603 SkDrawIter iter(this);
604
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000605#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000606 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700607 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000608 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000609 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000610
reedc83a2972015-07-16 07:40:45 -0700611#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
612 this->predrawNotify(bounds, &paint, auxOpaque); \
613 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
614 while (looper.next(type)) { \
615 SkDrawIter iter(this);
616
reed@google.com4e2b3d32011-04-07 14:18:59 +0000617#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000618
619////////////////////////////////////////////////////////////////////////////
620
mtkleinfeaadee2015-04-08 11:25:48 -0700621void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
622 this->restoreToCount(1);
623 fCachedLocalClipBounds.setEmpty();
624 fCachedLocalClipBoundsDirty = true;
625 fClipStack->reset();
626 fMCRec->reset(bounds);
627
628 // We're peering through a lot of structs here. Only at this scope do we
629 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
630 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
631}
632
reedd9544982014-09-09 18:46:22 -0700633SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
634 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
reed@google.comc0784db2013-12-13 21:16:12 +0000635 fCachedLocalClipBounds.setEmpty();
636 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000637 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000638 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700639 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800640 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700641 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642
halcanary385fe4d2015-08-26 13:07:48 -0700643 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700644
reed@android.com8a1c16f2008-12-17 15:59:43 +0000645 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700646 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647
reeda499f902015-05-01 09:34:31 -0700648 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
649 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
halcanary96fcdcc2015-08-27 07:41:13 -0700650 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700651
reed@android.com8a1c16f2008-12-17 15:59:43 +0000652 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653
halcanary96fcdcc2015-08-27 07:41:13 -0700654 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000655
reedf92c8662014-08-18 08:02:43 -0700656 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700657 // The root device and the canvas should always have the same pixel geometry
658 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700659 if (device->forceConservativeRasterClip()) {
660 fConservativeRasterClip = true;
661 }
reedf92c8662014-08-18 08:02:43 -0700662 device->onAttachToCanvas(this);
663 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800664 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700665 }
666 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667}
668
reed@google.comcde92112011-07-06 20:00:52 +0000669SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000670 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700671 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000672{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000673 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000674
halcanary96fcdcc2015-08-27 07:41:13 -0700675 this->init(nullptr, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000676}
677
reedd9544982014-09-09 18:46:22 -0700678static SkBitmap make_nopixels(int width, int height) {
679 SkBitmap bitmap;
680 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
681 return bitmap;
682}
683
684class SkNoPixelsBitmapDevice : public SkBitmapDevice {
685public:
robertphillipsfcf78292015-06-19 11:49:52 -0700686 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
687 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800688 {
689 this->setOrigin(bounds.x(), bounds.y());
690 }
reedd9544982014-09-09 18:46:22 -0700691
692private:
piotaixrb5fae932014-09-24 13:03:30 -0700693
reedd9544982014-09-09 18:46:22 -0700694 typedef SkBitmapDevice INHERITED;
695};
696
reed96a857e2015-01-25 10:33:58 -0800697SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000698 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800699 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000700{
701 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700702
halcanary385fe4d2015-08-26 13:07:48 -0700703 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
704 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700705}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000706
reed78e27682014-11-19 08:04:34 -0800707SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700708 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700709 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700710{
711 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700712
halcanary385fe4d2015-08-26 13:07:48 -0700713 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700714}
715
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000716SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000717 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700718 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000719{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000720 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700721
reedd9544982014-09-09 18:46:22 -0700722 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000723}
724
robertphillipsfcf78292015-06-19 11:49:52 -0700725SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
726 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700727 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700728{
729 inc_canvas();
730
731 this->init(device, flags);
732}
733
reed4a8126e2014-09-22 07:29:03 -0700734SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700735 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700736 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700737{
738 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700739
halcanary385fe4d2015-08-26 13:07:48 -0700740 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700741 this->init(device, kDefault_InitFlags);
742}
reed29c857d2014-09-21 10:25:07 -0700743
reed4a8126e2014-09-22 07:29:03 -0700744SkCanvas::SkCanvas(const SkBitmap& bitmap)
745 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
746 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
747{
748 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700749
halcanary385fe4d2015-08-26 13:07:48 -0700750 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700751 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000752}
753
754SkCanvas::~SkCanvas() {
755 // free up the contents of our deque
756 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000757
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758 this->internalRestore(); // restore the last, since we're going away
759
halcanary385fe4d2015-08-26 13:07:48 -0700760 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000761
reed@android.com8a1c16f2008-12-17 15:59:43 +0000762 dec_canvas();
763}
764
reed@android.com8a1c16f2008-12-17 15:59:43 +0000765SkDrawFilter* SkCanvas::getDrawFilter() const {
766 return fMCRec->fFilter;
767}
768
769SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700770 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
772 return filter;
773}
774
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000775SkMetaData& SkCanvas::getMetaData() {
776 // metadata users are rare, so we lazily allocate it. If that changes we
777 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700778 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000779 fMetaData = new SkMetaData;
780 }
781 return *fMetaData;
782}
783
reed@android.com8a1c16f2008-12-17 15:59:43 +0000784///////////////////////////////////////////////////////////////////////////////
785
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000786void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000787 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000788 if (device) {
789 device->flush();
790 }
791}
792
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000793SkISize SkCanvas::getTopLayerSize() const {
794 SkBaseDevice* d = this->getTopDevice();
795 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
796}
797
798SkIPoint SkCanvas::getTopLayerOrigin() const {
799 SkBaseDevice* d = this->getTopDevice();
800 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
801}
802
803SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000804 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000805 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
806}
807
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000808SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000810 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000811 SkASSERT(rec && rec->fLayer);
812 return rec->fLayer->fDevice;
813}
814
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000815SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000816 if (updateMatrixClip) {
817 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
818 }
reed@google.com9266fed2011-03-30 00:18:03 +0000819 return fMCRec->fTopLayer->fDevice;
820}
821
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000822bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
823 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
824 return false;
825 }
826
827 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700828 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700829 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000830 return false;
831 }
832 weAllocated = true;
833 }
834
reedcf01e312015-05-23 19:14:51 -0700835 SkAutoPixmapUnlock unlocker;
836 if (bitmap->requestLock(&unlocker)) {
837 const SkPixmap& pm = unlocker.pixmap();
838 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
839 return true;
840 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000841 }
842
843 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700844 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000845 }
846 return false;
847}
reed@google.com51df9e32010-12-23 19:29:18 +0000848
bsalomon@google.comc6980972011-11-02 19:57:21 +0000849bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000850 SkIRect r = srcRect;
851 const SkISize size = this->getBaseLayerSize();
852 if (!r.intersect(0, 0, size.width(), size.height())) {
853 bitmap->reset();
854 return false;
855 }
856
reed84825042014-09-02 12:50:45 -0700857 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000858 // bitmap will already be reset.
859 return false;
860 }
861 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
862 bitmap->reset();
863 return false;
864 }
865 return true;
866}
867
reed96472de2014-12-10 09:53:42 -0800868bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000869 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000870 if (!device) {
871 return false;
872 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000873 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800874
reed96472de2014-12-10 09:53:42 -0800875 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
876 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000877 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000878 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000879
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000880 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800881 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000882}
883
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000884bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
885 if (bitmap.getTexture()) {
886 return false;
887 }
reedcf01e312015-05-23 19:14:51 -0700888
889 SkAutoPixmapUnlock unlocker;
890 if (bitmap.requestLock(&unlocker)) {
891 const SkPixmap& pm = unlocker.pixmap();
892 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000893 }
894 return false;
895}
896
897bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
898 int x, int y) {
899 switch (origInfo.colorType()) {
900 case kUnknown_SkColorType:
901 case kIndex_8_SkColorType:
902 return false;
903 default:
904 break;
905 }
halcanary96fcdcc2015-08-27 07:41:13 -0700906 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000907 return false;
908 }
909
910 const SkISize size = this->getBaseLayerSize();
911 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
912 if (!target.intersect(0, 0, size.width(), size.height())) {
913 return false;
914 }
915
916 SkBaseDevice* device = this->getDevice();
917 if (!device) {
918 return false;
919 }
920
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000921 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700922 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000923
924 // if x or y are negative, then we have to adjust pixels
925 if (x > 0) {
926 x = 0;
927 }
928 if (y > 0) {
929 y = 0;
930 }
931 // here x,y are either 0 or negative
932 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
933
reed4af35f32014-06-27 17:47:49 -0700934 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700935 const bool completeOverwrite = info.dimensions() == size;
936 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700937
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000938 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000939 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000940}
reed@google.com51df9e32010-12-23 19:29:18 +0000941
junov@google.com4370aed2012-01-18 16:21:08 +0000942SkCanvas* SkCanvas::canvasForDrawIter() {
943 return this;
944}
945
reed@android.com8a1c16f2008-12-17 15:59:43 +0000946//////////////////////////////////////////////////////////////////////////////
947
reed@android.com8a1c16f2008-12-17 15:59:43 +0000948void SkCanvas::updateDeviceCMCache() {
949 if (fDeviceCMDirty) {
950 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700951 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000952 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000953
halcanary96fcdcc2015-08-27 07:41:13 -0700954 if (nullptr == layer->fNext) { // only one layer
955 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000956 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000957 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000958 do {
reed687fa1c2015-04-07 08:00:56 -0700959 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700960 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000961 }
962 fDeviceCMDirty = false;
963 }
964}
965
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966///////////////////////////////////////////////////////////////////////////////
967
reed2ff1fce2014-12-11 07:07:37 -0800968void SkCanvas::checkForDeferredSave() {
969 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800970 this->doSave();
971 }
972}
973
reedf0090cb2014-11-26 08:55:51 -0800974int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800975#ifdef SK_DEBUG
976 int count = 0;
977 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
978 for (;;) {
979 const MCRec* rec = (const MCRec*)iter.next();
980 if (!rec) {
981 break;
982 }
983 count += 1 + rec->fDeferredSaveCount;
984 }
985 SkASSERT(count == fSaveCount);
986#endif
987 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800988}
989
990int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800991 fSaveCount += 1;
992 fMCRec->fDeferredSaveCount += 1;
993 return this->getSaveCount() - 1; // return our prev value
994}
995
996void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800997 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700998
999 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1000 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001001 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001002}
1003
1004void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001005 if (fMCRec->fDeferredSaveCount > 0) {
1006 SkASSERT(fSaveCount > 1);
1007 fSaveCount -= 1;
1008 fMCRec->fDeferredSaveCount -= 1;
1009 } else {
1010 // check for underflow
1011 if (fMCStack.count() > 1) {
1012 this->willRestore();
1013 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001014 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001015 this->internalRestore();
1016 this->didRestore();
1017 }
reedf0090cb2014-11-26 08:55:51 -08001018 }
1019}
1020
1021void SkCanvas::restoreToCount(int count) {
1022 // sanity check
1023 if (count < 1) {
1024 count = 1;
1025 }
mtkleinf0f14112014-12-12 08:46:25 -08001026
reedf0090cb2014-11-26 08:55:51 -08001027 int n = this->getSaveCount() - count;
1028 for (int i = 0; i < n; ++i) {
1029 this->restore();
1030 }
1031}
1032
reed2ff1fce2014-12-11 07:07:37 -08001033void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001034 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001035 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001036 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001037
reed687fa1c2015-04-07 08:00:56 -07001038 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001039}
1040
reed@android.com8a1c16f2008-12-17 15:59:43 +00001041static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001042#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +00001043 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +00001044#else
1045 return true;
1046#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001047}
1048
junov@chromium.orga907ac32012-02-24 21:54:07 +00001049bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -07001050 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001051 SkIRect clipBounds;
1052 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001053 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001054 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001055
reed96e657d2015-03-10 17:30:07 -07001056 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1057
senorblanco87e066e2015-10-28 11:23:36 -07001058// This is a temporary hack, until individual filters can do their own
1059// bloating, when this will be removed.
1060#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
1061 SkRect storage;
1062#endif
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001063 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -07001064 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco87e066e2015-10-28 11:23:36 -07001065#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
1066 if (bounds && imageFilter->canComputeFastBounds()) {
1067 imageFilter->computeFastBounds(*bounds, &storage);
1068 bounds = &storage;
1069 } else {
1070 bounds = nullptr;
1071 }
1072#endif
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001073 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001074 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001075 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001076 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001077
reed96e657d2015-03-10 17:30:07 -07001078 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001079 r.roundOut(&ir);
1080 // early exit if the layer's bounds are clipped out
1081 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001082 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -07001083 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001084 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001085 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001086 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 }
1088 } else { // no user bounds, so just use the clip
1089 ir = clipBounds;
1090 }
reed180aec42015-03-11 10:39:04 -07001091 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001092
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +00001093 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -07001094 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -07001095 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -07001096 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001097 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001098 }
1099
1100 if (intersection) {
1101 *intersection = ir;
1102 }
1103 return true;
1104}
1105
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001106int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -08001107 if (gIgnoreSaveLayerBounds) {
halcanary96fcdcc2015-08-27 07:41:13 -07001108 bounds = nullptr;
reedd990e2f2014-12-22 11:58:30 -08001109 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001110 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -07001111 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -07001112 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -08001113 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001114}
1115
reed2ff1fce2014-12-11 07:07:37 -08001116int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -08001117 if (gIgnoreSaveLayerBounds) {
halcanary96fcdcc2015-08-27 07:41:13 -07001118 bounds = nullptr;
reedd990e2f2014-12-22 11:58:30 -08001119 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001120 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -07001121 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -07001122 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -08001123 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +00001124}
1125
reed2ff1fce2014-12-11 07:07:37 -08001126void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -07001127 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +00001128#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +00001129 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001130#endif
1131
junov@chromium.orga907ac32012-02-24 21:54:07 +00001132 // do this before we create the layer. We don't call the public save() since
1133 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001134 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001135
1136 fDeviceCMDirty = true;
1137
1138 SkIRect ir;
halcanary96fcdcc2015-08-27 07:41:13 -07001139 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : nullptr)) {
reed2ff1fce2014-12-11 07:07:37 -08001140 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141 }
1142
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001143 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1144 // the clipRectBounds() call above?
1145 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001146 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001147 }
1148
reed76033be2015-03-14 10:54:31 -07001149 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001150 SkPixelGeometry geo = fProps.pixelGeometry();
1151 if (paint) {
reed76033be2015-03-14 10:54:31 -07001152 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001153 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001154 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001155 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001156 }
1157 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001158 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1159 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001160
reedb2db8982014-11-13 12:41:02 -08001161 SkBaseDevice* device = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001162 if (nullptr == device) {
reedb2db8982014-11-13 12:41:02 -08001163 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001164 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001165 }
reedb2db8982014-11-13 12:41:02 -08001166
reed61f501f2015-04-29 08:34:00 -07001167 bool forceSpriteOnRestore = false;
1168 {
reeddaa57bf2015-05-15 10:39:17 -07001169 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed61f501f2015-04-29 08:34:00 -07001170 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo);
1171 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001172 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001173 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001174 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1175 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
halcanary96fcdcc2015-08-27 07:41:13 -07001176 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001177 SkErrorInternals::SetError(kInternalError_SkError,
1178 "Unable to create device for layer.");
1179 return;
1180 }
1181 forceSpriteOnRestore = true;
1182 }
1183 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001184 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001185
reed@google.com6f8f2922011-03-04 22:27:10 +00001186 device->setOrigin(ir.fLeft, ir.fTop);
halcanary385fe4d2015-08-26 13:07:48 -07001187 DeviceCM* layer =
1188 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001189 device->unref();
1190
1191 layer->fNext = fMCRec->fTopLayer;
1192 fMCRec->fLayer = layer;
1193 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001194}
1195
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001196int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1197 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1198}
1199
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1201 SaveFlags flags) {
1202 if (0xFF == alpha) {
halcanary96fcdcc2015-08-27 07:41:13 -07001203 return this->saveLayer(bounds, nullptr, flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001204 } else {
1205 SkPaint tmpPaint;
1206 tmpPaint.setAlpha(alpha);
1207 return this->saveLayer(bounds, &tmpPaint, flags);
1208 }
1209}
1210
reed@android.com8a1c16f2008-12-17 15:59:43 +00001211void SkCanvas::internalRestore() {
1212 SkASSERT(fMCStack.count() != 0);
1213
1214 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001215 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216
reed687fa1c2015-04-07 08:00:56 -07001217 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001218
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001219 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001220 DeviceCM* layer = fMCRec->fLayer; // may be null
1221 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001222 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223
1224 // now do the normal restore()
1225 fMCRec->~MCRec(); // balanced in save()
1226 fMCStack.pop_back();
1227 fMCRec = (MCRec*)fMCStack.back();
1228
1229 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1230 since if we're being recorded, we don't want to record this (the
1231 recorder will have already recorded the restore).
1232 */
bsalomon49f085d2014-09-05 13:34:00 -07001233 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001234 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001235 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001236 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001237 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001238 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001240 delete layer;
reedb679ca82015-04-07 04:40:48 -07001241 } else {
1242 // we're at the root
reeda499f902015-05-01 09:34:31 -07001243 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001244 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001246 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247}
1248
reed4a8126e2014-09-22 07:29:03 -07001249SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001250 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001251 props = &fProps;
1252 }
1253 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001254}
1255
reed4a8126e2014-09-22 07:29:03 -07001256SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001257 SkBaseDevice* dev = this->getDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001258 return dev ? dev->newSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001259}
1260
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001261SkImageInfo SkCanvas::imageInfo() const {
1262 SkBaseDevice* dev = this->getDevice();
1263 if (dev) {
1264 return dev->imageInfo();
1265 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001266 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001267 }
1268}
1269
1270const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001271 SkPixmap pmap;
1272 if (!this->onPeekPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001273 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001274 }
1275 if (info) {
1276 *info = pmap.info();
1277 }
1278 if (rowBytes) {
1279 *rowBytes = pmap.rowBytes();
1280 }
1281 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001282}
1283
reed884e97c2015-05-26 11:31:54 -07001284bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001285 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001286 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001287}
1288
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001289void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001290 SkPixmap pmap;
1291 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001292 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001293 }
1294 if (info) {
1295 *info = pmap.info();
1296 }
1297 if (rowBytes) {
1298 *rowBytes = pmap.rowBytes();
1299 }
1300 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001301 *origin = this->getTopDevice(false)->getOrigin();
1302 }
reed884e97c2015-05-26 11:31:54 -07001303 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001304}
1305
reed884e97c2015-05-26 11:31:54 -07001306bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001307 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001308 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001309}
1310
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001311SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1312 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -07001313 if (nullptr == fAddr) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001314 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001315 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001316 return; // failure, fAddr is nullptr
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001317 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001318 if (!canvas->readPixels(&fBitmap, 0, 0)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001319 return; // failure, fAddr is nullptr
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001320 }
1321 fAddr = fBitmap.getPixels();
1322 fRowBytes = fBitmap.rowBytes();
1323 }
1324 SkASSERT(fAddr); // success
1325}
1326
1327bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1328 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001329 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001330 } else {
1331 bitmap->reset();
1332 return false;
1333 }
1334}
1335
reed@android.com8a1c16f2008-12-17 15:59:43 +00001336/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001338void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001339 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001341 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342 paint = &tmp;
1343 }
reed@google.com4b226022011-01-11 18:32:13 +00001344
reed@google.com8926b162012-03-23 15:36:36 +00001345 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001347 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001348 paint = &looper.paint();
1349 SkImageFilter* filter = paint->getImageFilter();
1350 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001351 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001352 SkImageFilter::DeviceProxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001353 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001354 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001355 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001356 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001357 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001358 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001359 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reedc9b5f8b2015-10-22 13:20:20 -07001360 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(),
1361 SkImageFilter::kApprox_SizeConstraint);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001362 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001363 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001364 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001365 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1366 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001367 }
reed61f501f2015-04-29 08:34:00 -07001368 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001369 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001370 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001371 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001372 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001373 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001374 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001375 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001376}
1377
reed41af9662015-01-05 07:49:08 -08001378void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001379 if (gTreatSpriteAsBitmap) {
1380 this->save();
1381 this->resetMatrix();
1382 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1383 this->restore();
1384 return;
1385 }
1386
danakj9881d632014-11-26 12:41:06 -08001387 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001388 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001389 return;
1390 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001391 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001392
reed@google.com8926b162012-03-23 15:36:36 +00001393 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001394 if (nullptr == paint) {
reed@google.com8926b162012-03-23 15:36:36 +00001395 paint = &tmp;
1396 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001397
reed@google.com8926b162012-03-23 15:36:36 +00001398 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001399
reed@google.com8926b162012-03-23 15:36:36 +00001400 while (iter.next()) {
1401 paint = &looper.paint();
1402 SkImageFilter* filter = paint->getImageFilter();
1403 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1404 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001405 SkImageFilter::DeviceProxy proxy(iter.fDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001406 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001407 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001408 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001409 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001410 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001411 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
reedc9b5f8b2015-10-22 13:20:20 -07001412 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(),
1413 SkImageFilter::kApprox_SizeConstraint);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001414 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001415 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001416 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001417 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001418 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001419 }
1420 } else {
1421 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1422 }
1423 }
1424 LOOPER_END
1425}
1426
reed@android.com8a1c16f2008-12-17 15:59:43 +00001427/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001428void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001429 SkMatrix m;
1430 m.setTranslate(dx, dy);
1431 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001432}
1433
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001434void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001435 SkMatrix m;
1436 m.setScale(sx, sy);
1437 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001438}
1439
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001440void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001441 SkMatrix m;
1442 m.setRotate(degrees);
1443 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001444}
1445
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001446void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001447 SkMatrix m;
1448 m.setSkew(sx, sy);
1449 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001450}
1451
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001452void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001453 if (matrix.isIdentity()) {
1454 return;
1455 }
1456
reed2ff1fce2014-12-11 07:07:37 -08001457 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001458 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001459 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001460 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001461
1462 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001463}
1464
reed86a17e72015-05-14 12:25:22 -07001465void SkCanvas::setMatrix(const SkMatrix& matrix) {
1466 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001467 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001468 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001469 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001470 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001471}
1472
reed@android.com8a1c16f2008-12-17 15:59:43 +00001473void SkCanvas::resetMatrix() {
1474 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001475
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476 matrix.reset();
1477 this->setMatrix(matrix);
1478}
1479
1480//////////////////////////////////////////////////////////////////////////////
1481
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001482void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001483 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001484 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1485 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001486}
1487
1488void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001489#ifdef SK_ENABLE_CLIP_QUICKREJECT
1490 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001491 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001492 return false;
1493 }
1494
reed@google.com3b3e8952012-08-16 20:53:31 +00001495 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001496 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001497 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001498
reed687fa1c2015-04-07 08:00:56 -07001499 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001500 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001501 }
1502 }
1503#endif
1504
reed@google.com5c3d1472011-02-22 19:12:23 +00001505 AutoValidateClip avc(this);
1506
reed@android.com8a1c16f2008-12-17 15:59:43 +00001507 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001508 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001509 if (!fAllowSoftClip) {
1510 edgeStyle = kHard_ClipEdgeStyle;
1511 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001512
reed1f836ee2014-07-07 07:49:34 -07001513 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001514 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001515 // the matrix. This means we don't have to a) make a path, and b) tell
1516 // the region code to scan-convert the path, only to discover that it
1517 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001518 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001519
reed1f836ee2014-07-07 07:49:34 -07001520 fMCRec->fMatrix.mapRect(&r, rect);
reed687fa1c2015-04-07 08:00:56 -07001521 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001522 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001523 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001524 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001525 // and clip against that, since it can handle any matrix. However, to
1526 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1527 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001528 SkPath path;
1529
1530 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001531 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001532 }
1533}
1534
reed73e714e2014-09-04 09:02:23 -07001535static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1536 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001537 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001538}
1539
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001540void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001541 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001542 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001543 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001544 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1545 } else {
1546 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001547 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001548}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001549
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001550void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001551 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001552 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001553 AutoValidateClip avc(this);
1554
1555 fDeviceCMDirty = true;
1556 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001557 if (!fAllowSoftClip) {
1558 edgeStyle = kHard_ClipEdgeStyle;
1559 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001560
reed687fa1c2015-04-07 08:00:56 -07001561 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001562
1563 SkPath devPath;
1564 devPath.addRRect(transformedRRect);
1565
reed73e714e2014-09-04 09:02:23 -07001566 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001567 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001568 }
1569
1570 SkPath path;
1571 path.addRRect(rrect);
1572 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001573 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001574}
1575
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001576void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001577 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001578 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1579 SkRect r;
1580 if (!path.isInverseFillType() && path.isRect(&r)) {
1581 this->onClipRect(r, op, edgeStyle);
1582 } else {
1583 this->onClipPath(path, op, edgeStyle);
1584 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001585}
1586
1587void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001588#ifdef SK_ENABLE_CLIP_QUICKREJECT
1589 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001590 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001591 return false;
1592 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001593
reed@google.com3b3e8952012-08-16 20:53:31 +00001594 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001595 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001596 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001597
reed687fa1c2015-04-07 08:00:56 -07001598 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001599 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001600 }
1601 }
1602#endif
1603
reed@google.com5c3d1472011-02-22 19:12:23 +00001604 AutoValidateClip avc(this);
1605
reed@android.com8a1c16f2008-12-17 15:59:43 +00001606 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001607 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001608 if (!fAllowSoftClip) {
1609 edgeStyle = kHard_ClipEdgeStyle;
1610 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001611
1612 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001613 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001614
reed@google.comfe701122011-11-08 19:41:23 +00001615 // Check if the transfomation, or the original path itself
1616 // made us empty. Note this can also happen if we contained NaN
1617 // values. computing the bounds detects this, and will set our
1618 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1619 if (devPath.getBounds().isEmpty()) {
1620 // resetting the path will remove any NaN or other wanky values
1621 // that might upset our scan converter.
1622 devPath.reset();
1623 }
1624
reed@google.com5c3d1472011-02-22 19:12:23 +00001625 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001626 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001627
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001628 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001629 bool clipIsAA = getClipStack()->asPath(&devPath);
1630 if (clipIsAA) {
1631 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001632 }
fmalita1a481fe2015-02-04 07:39:34 -08001633
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001634 op = SkRegion::kReplace_Op;
1635 }
1636
reed73e714e2014-09-04 09:02:23 -07001637 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001638}
1639
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001640void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001641 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001642 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001643}
1644
1645void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001646 AutoValidateClip avc(this);
1647
reed@android.com8a1c16f2008-12-17 15:59:43 +00001648 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001649 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001650
reed@google.com5c3d1472011-02-22 19:12:23 +00001651 // todo: signal fClipStack that we have a region, and therefore (I guess)
1652 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001653 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001654
reed1f836ee2014-07-07 07:49:34 -07001655 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001656}
1657
reed@google.com819c9212011-02-23 18:56:55 +00001658#ifdef SK_DEBUG
1659void SkCanvas::validateClip() const {
1660 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001661 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001662 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001663 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001664 return;
1665 }
1666
reed@google.com819c9212011-02-23 18:56:55 +00001667 SkIRect ir;
1668 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001669 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001670
reed687fa1c2015-04-07 08:00:56 -07001671 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001672 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001673 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001674 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001675 case SkClipStack::Element::kRect_Type:
1676 element->getRect().round(&ir);
1677 tmpClip.op(ir, element->getOp());
1678 break;
1679 case SkClipStack::Element::kEmpty_Type:
1680 tmpClip.setEmpty();
1681 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001682 default: {
1683 SkPath path;
1684 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001685 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001686 break;
1687 }
reed@google.com819c9212011-02-23 18:56:55 +00001688 }
1689 }
reed@google.com819c9212011-02-23 18:56:55 +00001690}
1691#endif
1692
reed@google.com90c07ea2012-04-13 13:50:27 +00001693void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001694 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001695 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001696
halcanary96fcdcc2015-08-27 07:41:13 -07001697 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001698 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001699 }
1700}
1701
reed@google.com5c3d1472011-02-22 19:12:23 +00001702///////////////////////////////////////////////////////////////////////////////
1703
reed@google.com754de5f2014-02-24 19:38:20 +00001704bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001705 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001706}
1707
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001708bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001709 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001710}
1711
reed@google.com3b3e8952012-08-16 20:53:31 +00001712bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001713 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001714 return true;
1715
reed1f836ee2014-07-07 07:49:34 -07001716 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001717 return true;
1718 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001719
reed1f836ee2014-07-07 07:49:34 -07001720 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001721 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001722 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001723 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001724 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001725 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001726
reed@android.coma380ae42009-07-21 01:17:02 +00001727 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001728 // TODO: should we use | instead, or compare all 4 at once?
1729 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001730 return true;
1731 }
reed@google.comc0784db2013-12-13 21:16:12 +00001732 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001733 return true;
1734 }
1735 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001736 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001737}
1738
reed@google.com3b3e8952012-08-16 20:53:31 +00001739bool SkCanvas::quickReject(const SkPath& path) const {
1740 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001741}
1742
reed@google.com3b3e8952012-08-16 20:53:31 +00001743bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001744 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001745 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001746 return false;
1747 }
1748
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001749 SkMatrix inverse;
1750 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001751 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001752 if (bounds) {
1753 bounds->setEmpty();
1754 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001755 return false;
1756 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001757
bsalomon49f085d2014-09-05 13:34:00 -07001758 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001759 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001760 // adjust it outwards in case we are antialiasing
1761 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001762
reed@google.com8f4d2302013-12-17 16:44:46 +00001763 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1764 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001765 inverse.mapRect(bounds, r);
1766 }
1767 return true;
1768}
1769
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001770bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001771 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001772 if (clip.isEmpty()) {
1773 if (bounds) {
1774 bounds->setEmpty();
1775 }
1776 return false;
1777 }
1778
bsalomon49f085d2014-09-05 13:34:00 -07001779 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001780 *bounds = clip.getBounds();
1781 }
1782 return true;
1783}
1784
reed@android.com8a1c16f2008-12-17 15:59:43 +00001785const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001786 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001787}
1788
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001789const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001790 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001791}
1792
reed@google.com9c135db2014-03-12 18:28:35 +00001793GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1794 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001795 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001796}
1797
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001798GrContext* SkCanvas::getGrContext() {
1799#if SK_SUPPORT_GPU
1800 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001801 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001802 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001803 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001804 return renderTarget->getContext();
1805 }
1806 }
1807#endif
1808
halcanary96fcdcc2015-08-27 07:41:13 -07001809 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001810
1811}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001812
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001813void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1814 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001815 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001816 if (outer.isEmpty()) {
1817 return;
1818 }
1819 if (inner.isEmpty()) {
1820 this->drawRRect(outer, paint);
1821 return;
1822 }
1823
1824 // We don't have this method (yet), but technically this is what we should
1825 // be able to assert...
1826 // SkASSERT(outer.contains(inner));
1827 //
1828 // For now at least check for containment of bounds
1829 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1830
1831 this->onDrawDRRect(outer, inner, paint);
1832}
1833
reed41af9662015-01-05 07:49:08 -08001834// These need to stop being virtual -- clients need to override the onDraw... versions
1835
1836void SkCanvas::drawPaint(const SkPaint& paint) {
1837 this->onDrawPaint(paint);
1838}
1839
1840void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1841 this->onDrawRect(r, paint);
1842}
1843
1844void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1845 this->onDrawOval(r, paint);
1846}
1847
1848void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1849 this->onDrawRRect(rrect, paint);
1850}
1851
1852void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1853 this->onDrawPoints(mode, count, pts, paint);
1854}
1855
1856void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1857 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1858 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1859 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1860 indices, indexCount, paint);
1861}
1862
1863void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1864 this->onDrawPath(path, paint);
1865}
1866
reeda85d4d02015-05-06 12:56:48 -07001867void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1868 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001869}
1870
reede47829b2015-08-06 10:02:53 -07001871void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1872 const SkPaint* paint, SrcRectConstraint constraint) {
1873 if (dst.isEmpty() || src.isEmpty()) {
1874 return;
1875 }
1876 this->onDrawImageRect(image, &src, dst, paint, constraint);
1877}
reed41af9662015-01-05 07:49:08 -08001878
reed84984ef2015-07-17 07:09:43 -07001879void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1880 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001881 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001882}
1883
reede47829b2015-08-06 10:02:53 -07001884void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1885 SrcRectConstraint constraint) {
1886 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1887 constraint);
1888}
reede47829b2015-08-06 10:02:53 -07001889
reed4c21dc52015-06-25 12:32:03 -07001890void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1891 const SkPaint* paint) {
1892 if (dst.isEmpty()) {
1893 return;
1894 }
1895 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001896 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001897 }
1898 this->onDrawImageNine(image, center, dst, paint);
1899}
1900
reed41af9662015-01-05 07:49:08 -08001901void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001902 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001903 return;
1904 }
reed41af9662015-01-05 07:49:08 -08001905 this->onDrawBitmap(bitmap, dx, dy, paint);
1906}
1907
reede47829b2015-08-06 10:02:53 -07001908void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001909 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001910 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001911 return;
1912 }
reede47829b2015-08-06 10:02:53 -07001913 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001914}
1915
reed84984ef2015-07-17 07:09:43 -07001916void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1917 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001918 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001919}
1920
reede47829b2015-08-06 10:02:53 -07001921void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1922 SrcRectConstraint constraint) {
1923 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1924 constraint);
1925}
reede47829b2015-08-06 10:02:53 -07001926
reed41af9662015-01-05 07:49:08 -08001927void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1928 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001929 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001930 return;
1931 }
reed4c21dc52015-06-25 12:32:03 -07001932 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001933 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001934 }
reed41af9662015-01-05 07:49:08 -08001935 this->onDrawBitmapNine(bitmap, center, dst, paint);
1936}
1937
1938void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001939 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001940 return;
1941 }
reed41af9662015-01-05 07:49:08 -08001942 this->onDrawSprite(bitmap, left, top, paint);
1943}
1944
reed71c3c762015-06-24 10:29:17 -07001945void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1946 const SkColor colors[], int count, SkXfermode::Mode mode,
1947 const SkRect* cull, const SkPaint* paint) {
1948 if (count <= 0) {
1949 return;
1950 }
1951 SkASSERT(atlas);
1952 SkASSERT(xform);
1953 SkASSERT(tex);
1954 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1955}
1956
reede47829b2015-08-06 10:02:53 -07001957void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1958 const SkPaint* paint, SrcRectConstraint constraint) {
1959 if (src) {
1960 this->drawImageRect(image, *src, dst, paint, constraint);
1961 } else {
1962 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1963 dst, paint, constraint);
1964 }
1965}
1966void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1967 const SkPaint* paint, SrcRectConstraint constraint) {
1968 if (src) {
1969 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1970 } else {
1971 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1972 dst, paint, constraint);
1973 }
1974}
1975
reed@android.com8a1c16f2008-12-17 15:59:43 +00001976//////////////////////////////////////////////////////////////////////////////
1977// These are the virtual drawing methods
1978//////////////////////////////////////////////////////////////////////////////
1979
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001980void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001981 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001982 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1983 }
1984}
1985
reed41af9662015-01-05 07:49:08 -08001986void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001987 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001988 this->internalDrawPaint(paint);
1989}
1990
1991void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001992 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001993
1994 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001995 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001996 }
1997
reed@google.com4e2b3d32011-04-07 14:18:59 +00001998 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001999}
2000
reed41af9662015-01-05 07:49:08 -08002001void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2002 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002003 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002004 if ((long)count <= 0) {
2005 return;
2006 }
2007
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002008 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002009 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002010 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002011 // special-case 2 points (common for drawing a single line)
2012 if (2 == count) {
2013 r.set(pts[0], pts[1]);
2014 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002015 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002016 }
senorblanco87e066e2015-10-28 11:23:36 -07002017#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002018 bounds = &paint.computeFastStrokeBounds(r, &storage);
2019 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00002020 return;
2021 }
senorblanco87e066e2015-10-28 11:23:36 -07002022#else
2023 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2024 return;
2025 }
2026 bounds = &r;
2027#endif
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002028 }
reed@google.coma584aed2012-05-16 14:06:02 +00002029
halcanary96fcdcc2015-08-27 07:41:13 -07002030 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002031
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002032 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002033
reed@android.com8a1c16f2008-12-17 15:59:43 +00002034 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002035 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002036 }
reed@google.com4b226022011-01-11 18:32:13 +00002037
reed@google.com4e2b3d32011-04-07 14:18:59 +00002038 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002039}
2040
reed41af9662015-01-05 07:49:08 -08002041void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002042 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002043 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002044 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002045 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002046 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2047 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2048 SkRect tmp(r);
2049 tmp.sort();
2050
senorblanco87e066e2015-10-28 11:23:36 -07002051#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
reed84328082015-02-10 14:18:09 -08002052 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002053 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002054 return;
2055 }
senorblanco87e066e2015-10-28 11:23:36 -07002056#else
2057 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2058 return;
2059 }
2060 bounds = &r;
2061#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002062 }
reed@google.com4b226022011-01-11 18:32:13 +00002063
reedc83a2972015-07-16 07:40:45 -07002064 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002065
2066 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002067 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002068 }
2069
reed@google.com4e2b3d32011-04-07 14:18:59 +00002070 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002071}
2072
reed41af9662015-01-05 07:49:08 -08002073void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002074 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002075 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002076 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002077 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002078#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002079 bounds = &paint.computeFastBounds(oval, &storage);
2080 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002081 return;
2082 }
senorblanco87e066e2015-10-28 11:23:36 -07002083#else
2084 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2085 return;
2086 }
2087 bounds = &oval;
2088#endif
reed@google.com4ed0fb72012-12-12 20:48:18 +00002089 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002090
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002091 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002092
2093 while (iter.next()) {
2094 iter.fDevice->drawOval(iter, oval, looper.paint());
2095 }
2096
2097 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002098}
2099
reed41af9662015-01-05 07:49:08 -08002100void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002101 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002102 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002103 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002104 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002105#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002106 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
2107 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002108 return;
2109 }
senorblanco87e066e2015-10-28 11:23:36 -07002110#else
2111 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2112 return;
2113 }
2114 bounds = &rrect.getBounds();
2115#endif
reed@google.com4ed0fb72012-12-12 20:48:18 +00002116 }
2117
2118 if (rrect.isRect()) {
2119 // call the non-virtual version
2120 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002121 return;
2122 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002123 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002124 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2125 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002126 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002127
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002128 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002129
2130 while (iter.next()) {
2131 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2132 }
2133
2134 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002135}
2136
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002137void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2138 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002139 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002140 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002141 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002142#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002143 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
2144 if (this->quickReject(*bounds)) {
2145 return;
2146 }
senorblanco87e066e2015-10-28 11:23:36 -07002147#else
2148 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2149 return;
2150 }
2151 bounds = &outer.getBounds();
2152#endif
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002153 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002154
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002155 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002156
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002157 while (iter.next()) {
2158 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2159 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002160
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002161 LOOPER_END
2162}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002163
reed41af9662015-01-05 07:49:08 -08002164void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002165 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002166 if (!path.isFinite()) {
2167 return;
2168 }
2169
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002170 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002171 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002172 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002173 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002174#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002175 bounds = &paint.computeFastBounds(pathBounds, &storage);
2176 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002177 return;
2178 }
senorblanco87e066e2015-10-28 11:23:36 -07002179#else
2180 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2181 return;
2182 }
2183 bounds = &pathBounds;
2184#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002185 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002186
2187 const SkRect& r = path.getBounds();
2188 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002189 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002190 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002191 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002192 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002193 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002194
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002195 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002196
2197 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002198 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002199 }
2200
reed@google.com4e2b3d32011-04-07 14:18:59 +00002201 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002202}
2203
reeda85d4d02015-05-06 12:56:48 -07002204void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002205 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002206 SkRect bounds = SkRect::MakeXYWH(x, y,
2207 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002208 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002209#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
reeda85d4d02015-05-06 12:56:48 -07002210 if (paint) {
2211 paint->computeFastBounds(bounds, &bounds);
2212 }
2213 if (this->quickReject(bounds)) {
2214 return;
2215 }
senorblanco87e066e2015-10-28 11:23:36 -07002216#else
2217 SkRect tmp = bounds;
2218 if (paint) {
2219 paint->computeFastBounds(tmp, &tmp);
2220 }
2221 if (this->quickReject(tmp)) {
2222 return;
2223 }
2224#endif
reeda85d4d02015-05-06 12:56:48 -07002225 }
2226
2227 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002228 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002229 paint = lazy.init();
2230 }
2231
2232 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds)
2233
2234 while (iter.next()) {
2235 iter.fDevice->drawImage(iter, image, x, y, looper.paint());
2236 }
2237
2238 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002239}
2240
reed41af9662015-01-05 07:49:08 -08002241void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002242 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002243 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
reeda85d4d02015-05-06 12:56:48 -07002244 SkRect storage;
2245 const SkRect* bounds = &dst;
halcanary96fcdcc2015-08-27 07:41:13 -07002246 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002247#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
reeda85d4d02015-05-06 12:56:48 -07002248 if (paint) {
2249 bounds = &paint->computeFastBounds(dst, &storage);
2250 }
2251 if (this->quickReject(*bounds)) {
2252 return;
2253 }
senorblanco87e066e2015-10-28 11:23:36 -07002254#else
2255 storage = dst;
2256 if (paint) {
2257 paint->computeFastBounds(dst, &storage);
2258 }
2259 if (this->quickReject(storage)) {
2260 return;
2261 }
2262#endif
reeda85d4d02015-05-06 12:56:48 -07002263 }
2264 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002265 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002266 paint = lazy.init();
2267 }
2268
reedc83a2972015-07-16 07:40:45 -07002269 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, bounds,
2270 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002271
2272 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002273 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002274 }
2275
2276 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002277}
2278
reed41af9662015-01-05 07:49:08 -08002279void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002280 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002281 SkDEBUGCODE(bitmap.validate();)
2282
reed33366972015-10-08 09:22:02 -07002283 if (bitmap.drawsNothing()) {
2284 return;
2285 }
2286
2287 SkLazyPaint lazy;
2288 if (nullptr == paint) {
2289 paint = lazy.init();
2290 }
2291
2292 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2293
2294 SkRect storage;
2295 const SkRect* bounds = nullptr;
2296 if (paint->canComputeFastBounds()) {
2297 bitmap.getBounds(&storage);
2298 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002299#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
reed33366972015-10-08 09:22:02 -07002300 bounds = &paint->computeFastBounds(storage, &storage);
2301 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302 return;
2303 }
senorblanco87e066e2015-10-28 11:23:36 -07002304#else
2305 SkRect tmp = storage;
2306 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2307 return;
2308 }
2309 bounds = &storage;
2310#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002311 }
reed@google.com4b226022011-01-11 18:32:13 +00002312
reed33366972015-10-08 09:22:02 -07002313 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2314
2315 while (iter.next()) {
2316 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2317 }
2318
2319 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002320}
2321
reed@google.com9987ec32011-09-07 11:57:52 +00002322// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002323void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002324 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002325 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002326 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002327 return;
2328 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002329
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002330 SkRect storage;
2331 const SkRect* bounds = &dst;
halcanary96fcdcc2015-08-27 07:41:13 -07002332 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002333#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
reed@google.com9efd9a02012-01-30 15:41:43 +00002334 if (paint) {
2335 bounds = &paint->computeFastBounds(dst, &storage);
2336 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002337 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002338 return;
2339 }
senorblanco87e066e2015-10-28 11:23:36 -07002340#else
2341 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2342 return;
2343 }
2344#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00002345 }
reed@google.com3d608122011-11-21 15:16:16 +00002346
reed@google.com33535f32012-09-25 15:37:50 +00002347 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002348 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002349 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002350 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002351
reedc83a2972015-07-16 07:40:45 -07002352 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, bounds,
2353 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002354
reed@google.com33535f32012-09-25 15:37:50 +00002355 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002356 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002357 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002358
reed@google.com33535f32012-09-25 15:37:50 +00002359 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002360}
2361
reed41af9662015-01-05 07:49:08 -08002362void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002363 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002364 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002365 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002366 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002367}
2368
reed4c21dc52015-06-25 12:32:03 -07002369void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2370 const SkPaint* paint) {
2371 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2372
2373 SkRect storage;
2374 const SkRect* bounds = &dst;
halcanary96fcdcc2015-08-27 07:41:13 -07002375 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002376#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
djsollen@google.com60abb072012-02-15 18:49:15 +00002377 if (paint) {
2378 bounds = &paint->computeFastBounds(dst, &storage);
2379 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002380 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002381 return;
2382 }
senorblanco87e066e2015-10-28 11:23:36 -07002383#else
2384 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2385 return;
2386 }
2387#endif
reed@google.com3d608122011-11-21 15:16:16 +00002388 }
reed4c21dc52015-06-25 12:32:03 -07002389
2390 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002391 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002392 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002393 }
reed4c21dc52015-06-25 12:32:03 -07002394
2395 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2396
2397 while (iter.next()) {
2398 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002399 }
reed4c21dc52015-06-25 12:32:03 -07002400
2401 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002402}
2403
reed41af9662015-01-05 07:49:08 -08002404void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2405 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002406 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002407 SkDEBUGCODE(bitmap.validate();)
2408
reed4c21dc52015-06-25 12:32:03 -07002409 SkRect storage;
2410 const SkRect* bounds = &dst;
halcanary96fcdcc2015-08-27 07:41:13 -07002411 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002412#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
reed4c21dc52015-06-25 12:32:03 -07002413 if (paint) {
2414 bounds = &paint->computeFastBounds(dst, &storage);
2415 }
2416 if (this->quickReject(*bounds)) {
2417 return;
2418 }
senorblanco87e066e2015-10-28 11:23:36 -07002419#else
2420 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2421 return;
2422 }
2423#endif
reed4c21dc52015-06-25 12:32:03 -07002424 }
2425
2426 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002427 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002428 paint = lazy.init();
2429 }
2430
2431 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2432
2433 while (iter.next()) {
2434 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2435 }
2436
2437 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002438}
2439
reed@google.comf67e4cf2011-03-15 20:56:58 +00002440class SkDeviceFilteredPaint {
2441public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002442 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002443 uint32_t filteredFlags = device->filterTextFlags(paint);
2444 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002445 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002446 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002447 fPaint = newPaint;
2448 } else {
2449 fPaint = &paint;
2450 }
2451 }
2452
reed@google.comf67e4cf2011-03-15 20:56:58 +00002453 const SkPaint& paint() const { return *fPaint; }
2454
2455private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002456 const SkPaint* fPaint;
2457 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002458};
2459
bungeman@google.com52c748b2011-08-22 21:30:43 +00002460void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2461 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002462 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002463 draw.fDevice->drawRect(draw, r, paint);
2464 } else {
2465 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002466 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002467 draw.fDevice->drawRect(draw, r, p);
2468 }
2469}
2470
2471void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2472 const char text[], size_t byteLength,
2473 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002474 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002475
2476 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002477 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002478 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002479 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002480 return;
2481 }
2482
2483 SkScalar width = 0;
2484 SkPoint start;
2485
2486 start.set(0, 0); // to avoid warning
2487 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2488 SkPaint::kStrikeThruText_Flag)) {
2489 width = paint.measureText(text, byteLength);
2490
2491 SkScalar offsetX = 0;
2492 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2493 offsetX = SkScalarHalf(width);
2494 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2495 offsetX = width;
2496 }
2497 start.set(x - offsetX, y);
2498 }
2499
2500 if (0 == width) {
2501 return;
2502 }
2503
2504 uint32_t flags = paint.getFlags();
2505
2506 if (flags & (SkPaint::kUnderlineText_Flag |
2507 SkPaint::kStrikeThruText_Flag)) {
2508 SkScalar textSize = paint.getTextSize();
2509 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2510 SkRect r;
2511
2512 r.fLeft = start.fX;
2513 r.fRight = start.fX + width;
2514
2515 if (flags & SkPaint::kUnderlineText_Flag) {
2516 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2517 start.fY);
2518 r.fTop = offset;
2519 r.fBottom = offset + height;
2520 DrawRect(draw, paint, r, textSize);
2521 }
2522 if (flags & SkPaint::kStrikeThruText_Flag) {
2523 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2524 start.fY);
2525 r.fTop = offset;
2526 r.fBottom = offset + height;
2527 DrawRect(draw, paint, r, textSize);
2528 }
2529 }
2530}
2531
reed@google.come0d9ce82014-04-23 04:00:17 +00002532void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2533 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002534 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002535
2536 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002537 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002538 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002539 DrawTextDecorations(iter, dfp.paint(),
2540 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002541 }
2542
reed@google.com4e2b3d32011-04-07 14:18:59 +00002543 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002544}
2545
reed@google.come0d9ce82014-04-23 04:00:17 +00002546void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2547 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002548 SkPoint textOffset = SkPoint::Make(0, 0);
2549
halcanary96fcdcc2015-08-27 07:41:13 -07002550 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002551
reed@android.com8a1c16f2008-12-17 15:59:43 +00002552 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002553 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002554 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002555 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002556 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002557
reed@google.com4e2b3d32011-04-07 14:18:59 +00002558 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002559}
2560
reed@google.come0d9ce82014-04-23 04:00:17 +00002561void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2562 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002563
2564 SkPoint textOffset = SkPoint::Make(0, constY);
2565
halcanary96fcdcc2015-08-27 07:41:13 -07002566 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002567
reed@android.com8a1c16f2008-12-17 15:59:43 +00002568 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002569 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002570 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002571 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002572 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002573
reed@google.com4e2b3d32011-04-07 14:18:59 +00002574 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002575}
2576
reed@google.come0d9ce82014-04-23 04:00:17 +00002577void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2578 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002579 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002580
reed@android.com8a1c16f2008-12-17 15:59:43 +00002581 while (iter.next()) {
2582 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002583 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002584 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002585
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002586 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002587}
2588
fmalita00d5c2c2014-08-21 08:53:26 -07002589void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2590 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002591
fmalita85d5eb92015-03-04 11:20:12 -08002592 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002593 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002594 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002595 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002596#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED
fmalita85d5eb92015-03-04 11:20:12 -08002597 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002598
fmalita85d5eb92015-03-04 11:20:12 -08002599 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002600 return;
2601 }
senorblanco87e066e2015-10-28 11:23:36 -07002602#else
2603 SkRect tmp;
2604 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2605 return;
2606 }
2607 bounds = &storage;
2608#endif
fmalita7ba7aa72014-08-29 09:46:36 -07002609 }
2610
fmalita024f9962015-03-03 19:08:17 -08002611 // We cannot filter in the looper as we normally do, because the paint is
2612 // incomplete at this point (text-related attributes are embedded within blob run paints).
2613 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002614 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002615
fmalita85d5eb92015-03-04 11:20:12 -08002616 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002617
fmalitaaa1b9122014-08-28 14:32:24 -07002618 while (iter.next()) {
2619 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002620 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002621 }
2622
fmalitaaa1b9122014-08-28 14:32:24 -07002623 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002624
2625 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002626}
2627
reed@google.come0d9ce82014-04-23 04:00:17 +00002628// These will become non-virtual, so they always call the (virtual) onDraw... method
2629void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2630 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002631 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002632 this->onDrawText(text, byteLength, x, y, paint);
2633}
2634void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2635 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002636 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002637 this->onDrawPosText(text, byteLength, pos, paint);
2638}
2639void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2640 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002641 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002642 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2643}
2644void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2645 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002646 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002647 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2648}
fmalita00d5c2c2014-08-21 08:53:26 -07002649void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2650 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002651 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002652 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002653 this->onDrawTextBlob(blob, x, y, paint);
2654 }
2655}
reed@google.come0d9ce82014-04-23 04:00:17 +00002656
reed41af9662015-01-05 07:49:08 -08002657void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2658 const SkPoint verts[], const SkPoint texs[],
2659 const SkColor colors[], SkXfermode* xmode,
2660 const uint16_t indices[], int indexCount,
2661 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002662 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002663 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002664
reed@android.com8a1c16f2008-12-17 15:59:43 +00002665 while (iter.next()) {
2666 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002667 colors, xmode, indices, indexCount,
2668 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002669 }
reed@google.com4b226022011-01-11 18:32:13 +00002670
reed@google.com4e2b3d32011-04-07 14:18:59 +00002671 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002672}
2673
dandovb3c9d1c2014-08-12 08:34:29 -07002674void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2675 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002676 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002677 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002678 return;
2679 }
mtklein6cfa73a2014-08-13 13:33:49 -07002680
dandovecfff212014-08-04 10:02:00 -07002681 // Since a patch is always within the convex hull of the control points, we discard it when its
2682 // bounding rectangle is completely outside the current clip.
2683 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002684 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002685 if (this->quickReject(bounds)) {
2686 return;
2687 }
mtklein6cfa73a2014-08-13 13:33:49 -07002688
dandovb3c9d1c2014-08-12 08:34:29 -07002689 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2690}
2691
2692void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2693 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2694
halcanary96fcdcc2015-08-27 07:41:13 -07002695 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002696
dandovecfff212014-08-04 10:02:00 -07002697 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002698 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002699 }
mtklein6cfa73a2014-08-13 13:33:49 -07002700
dandovecfff212014-08-04 10:02:00 -07002701 LOOPER_END
2702}
2703
reeda8db7282015-07-07 10:22:31 -07002704void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2705 if (dr) {
2706 if (x || y) {
2707 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2708 this->onDrawDrawable(dr, &matrix);
2709 } else {
halcanary96fcdcc2015-08-27 07:41:13 -07002710 this->onDrawDrawable(dr, nullptr);
reeda8db7282015-07-07 10:22:31 -07002711 }
reed6a070dc2014-11-11 19:36:09 -08002712 }
2713}
2714
reeda8db7282015-07-07 10:22:31 -07002715void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2716 if (dr) {
2717 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002718 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002719 }
2720 this->onDrawDrawable(dr, matrix);
2721 }
2722}
2723
2724void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2725 SkRect bounds = dr->getBounds();
2726 if (matrix) {
2727 matrix->mapRect(&bounds);
2728 }
2729 if (this->quickReject(bounds)) {
2730 return;
2731 }
2732 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002733}
2734
reed71c3c762015-06-24 10:29:17 -07002735void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2736 const SkColor colors[], int count, SkXfermode::Mode mode,
2737 const SkRect* cull, const SkPaint* paint) {
2738 if (cull && this->quickReject(*cull)) {
2739 return;
2740 }
2741
2742 SkPaint pnt;
2743 if (paint) {
2744 pnt = *paint;
2745 }
2746
halcanary96fcdcc2015-08-27 07:41:13 -07002747 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002748 while (iter.next()) {
2749 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2750 }
2751 LOOPER_END
2752}
2753
reed@android.com8a1c16f2008-12-17 15:59:43 +00002754//////////////////////////////////////////////////////////////////////////////
2755// These methods are NOT virtual, and therefore must call back into virtual
2756// methods, rather than actually drawing themselves.
2757//////////////////////////////////////////////////////////////////////////////
2758
2759void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002760 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002761 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002762 SkPaint paint;
2763
2764 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002765 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002766 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002767 }
2768 this->drawPaint(paint);
2769}
2770
reed@android.com845fdac2009-06-23 03:01:32 +00002771void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002772 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002773 SkPaint paint;
2774
2775 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002776 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002777 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002778 }
2779 this->drawPaint(paint);
2780}
2781
2782void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002783 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002784 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002785
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786 pt.set(x, y);
2787 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2788}
2789
2790void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002791 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002792 SkPoint pt;
2793 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002794
reed@android.com8a1c16f2008-12-17 15:59:43 +00002795 pt.set(x, y);
2796 paint.setColor(color);
2797 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2798}
2799
2800void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2801 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002802 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002803 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002804
reed@android.com8a1c16f2008-12-17 15:59:43 +00002805 pts[0].set(x0, y0);
2806 pts[1].set(x1, y1);
2807 this->drawPoints(kLines_PointMode, 2, pts, paint);
2808}
2809
2810void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2811 SkScalar right, SkScalar bottom,
2812 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002813 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002814 SkRect r;
2815
2816 r.set(left, top, right, bottom);
2817 this->drawRect(r, paint);
2818}
2819
2820void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2821 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002822 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002823 if (radius < 0) {
2824 radius = 0;
2825 }
2826
2827 SkRect r;
2828 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002829 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002830}
2831
2832void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2833 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002834 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002835 if (rx > 0 && ry > 0) {
2836 if (paint.canComputeFastBounds()) {
2837 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002838 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002839 return;
2840 }
2841 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002842 SkRRect rrect;
2843 rrect.setRectXY(r, rx, ry);
2844 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002845 } else {
2846 this->drawRect(r, paint);
2847 }
2848}
2849
reed@android.com8a1c16f2008-12-17 15:59:43 +00002850void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2851 SkScalar sweepAngle, bool useCenter,
2852 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002853 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002854 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2855 this->drawOval(oval, paint);
2856 } else {
2857 SkPath path;
2858 if (useCenter) {
2859 path.moveTo(oval.centerX(), oval.centerY());
2860 }
2861 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2862 if (useCenter) {
2863 path.close();
2864 }
2865 this->drawPath(path, paint);
2866 }
2867}
2868
2869void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2870 const SkPath& path, SkScalar hOffset,
2871 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002872 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002873 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002874
reed@android.com8a1c16f2008-12-17 15:59:43 +00002875 matrix.setTranslate(hOffset, vOffset);
2876 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2877}
2878
reed@android.comf76bacf2009-05-13 14:00:33 +00002879///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002880
2881/**
2882 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2883 * against the playback cost of recursing into the subpicture to get at its actual ops.
2884 *
2885 * For now we pick a conservatively small value, though measurement (and other heuristics like
2886 * the type of ops contained) may justify changing this value.
2887 */
2888#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002889
reedd5fa1a42014-08-09 11:08:05 -07002890void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002891 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002892 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002893 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002894 matrix = nullptr;
reedd5fa1a42014-08-09 11:08:05 -07002895 }
reed1c2c4412015-04-30 13:09:24 -07002896 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2897 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2898 picture->playback(this);
2899 } else {
2900 this->onDrawPicture(picture, matrix, paint);
2901 }
reedd5fa1a42014-08-09 11:08:05 -07002902 }
2903}
robertphillips9b14f262014-06-04 05:40:44 -07002904
reedd5fa1a42014-08-09 11:08:05 -07002905void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2906 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002907 if (!paint || paint->canComputeFastBounds()) {
2908 SkRect bounds = picture->cullRect();
2909 if (paint) {
2910 paint->computeFastBounds(bounds, &bounds);
2911 }
2912 if (matrix) {
2913 matrix->mapRect(&bounds);
2914 }
2915 if (this->quickReject(bounds)) {
2916 return;
2917 }
2918 }
2919
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002920 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002921 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002922 // Canvas has to first give the device the opportunity to render
2923 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002924 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002925 return; // the device has rendered the entire picture
2926 }
2927 }
2928
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002929 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002930 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002931}
2932
reed@android.com8a1c16f2008-12-17 15:59:43 +00002933///////////////////////////////////////////////////////////////////////////////
2934///////////////////////////////////////////////////////////////////////////////
2935
2936SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002937 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002938
2939 SkASSERT(canvas);
2940
2941 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2942 fDone = !fImpl->next();
2943}
2944
2945SkCanvas::LayerIter::~LayerIter() {
2946 fImpl->~SkDrawIter();
2947}
2948
2949void SkCanvas::LayerIter::next() {
2950 fDone = !fImpl->next();
2951}
2952
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002953SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002954 return fImpl->getDevice();
2955}
2956
2957const SkMatrix& SkCanvas::LayerIter::matrix() const {
2958 return fImpl->getMatrix();
2959}
2960
2961const SkPaint& SkCanvas::LayerIter::paint() const {
2962 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002963 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002964 paint = &fDefaultPaint;
2965 }
2966 return *paint;
2967}
2968
2969const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2970int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2971int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002972
2973///////////////////////////////////////////////////////////////////////////////
2974
fmalitac3b589a2014-06-05 12:40:07 -07002975SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002976
2977///////////////////////////////////////////////////////////////////////////////
2978
2979static bool supported_for_raster_canvas(const SkImageInfo& info) {
2980 switch (info.alphaType()) {
2981 case kPremul_SkAlphaType:
2982 case kOpaque_SkAlphaType:
2983 break;
2984 default:
2985 return false;
2986 }
2987
2988 switch (info.colorType()) {
2989 case kAlpha_8_SkColorType:
2990 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002991 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002992 break;
2993 default:
2994 return false;
2995 }
2996
2997 return true;
2998}
2999
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003000SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
3001 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003002 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003003 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00003004
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003005 SkBitmap bitmap;
3006 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07003007 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003008 }
halcanary385fe4d2015-08-26 13:07:48 -07003009 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00003010}
reedd5fa1a42014-08-09 11:08:05 -07003011
3012///////////////////////////////////////////////////////////////////////////////
3013
3014SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003015 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07003016 : fCanvas(canvas)
3017 , fSaveCount(canvas->getSaveCount())
3018{
bsalomon49f085d2014-09-05 13:34:00 -07003019 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003020 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07003021 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003022 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07003023 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07003024 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07003025 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003026 canvas->save();
3027 }
mtklein6cfa73a2014-08-13 13:33:49 -07003028
bsalomon49f085d2014-09-05 13:34:00 -07003029 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07003030 canvas->concat(*matrix);
3031 }
3032}
3033
3034SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3035 fCanvas->restoreToCount(fSaveCount);
3036}