blob: ef7b1e799b011b33cdd6c28cb0610695faa5272b [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#define SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
senorblanco87e066e2015-10-28 11:23:36 -070042
reedc83a2972015-07-16 07:40:45 -070043/*
44 * Return true if the drawing this rect would hit every pixels in the canvas.
45 *
46 * Returns false if
47 * - rect does not contain the canvas' bounds
48 * - paint is not fill
49 * - paint would blur or otherwise change the coverage of the rect
50 */
51bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
52 ShaderOverrideOpacity overrideOpacity) const {
bungeman99fe8222015-08-20 07:57:51 -070053 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
54 (int)kNone_ShaderOverrideOpacity,
55 "need_matching_enums0");
56 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
57 (int)kOpaque_ShaderOverrideOpacity,
58 "need_matching_enums1");
59 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
60 (int)kNotOpaque_ShaderOverrideOpacity,
61 "need_matching_enums2");
reedc83a2972015-07-16 07:40:45 -070062
63 const SkISize size = this->getBaseLayerSize();
64 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
65 if (!this->getClipStack()->quickContains(bounds)) {
66 return false;
67 }
68
69 if (rect) {
70 if (!this->getTotalMatrix().rectStaysRect()) {
71 return false; // conservative
72 }
73
74 SkRect devRect;
75 this->getTotalMatrix().mapRect(&devRect, *rect);
fmalita8c0144c2015-07-22 05:56:16 -070076 if (!devRect.contains(bounds)) {
reedc83a2972015-07-16 07:40:45 -070077 return false;
78 }
79 }
80
81 if (paint) {
82 SkPaint::Style paintStyle = paint->getStyle();
83 if (!(paintStyle == SkPaint::kFill_Style ||
84 paintStyle == SkPaint::kStrokeAndFill_Style)) {
85 return false;
86 }
87 if (paint->getMaskFilter() || paint->getLooper()
88 || paint->getPathEffect() || paint->getImageFilter()) {
89 return false; // conservative
90 }
91 }
92 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
93}
94
95///////////////////////////////////////////////////////////////////////////////////////////////////
96
reedd990e2f2014-12-22 11:58:30 -080097static bool gIgnoreSaveLayerBounds;
98void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
99 gIgnoreSaveLayerBounds = ignore;
100}
101bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
102 return gIgnoreSaveLayerBounds;
103}
104
reed0acf1b42014-12-22 16:12:38 -0800105static bool gTreatSpriteAsBitmap;
106void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
107 gTreatSpriteAsBitmap = spriteAsBitmap;
108}
109bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
110 return gTreatSpriteAsBitmap;
111}
112
reed@google.comda17f752012-08-16 18:27:05 +0000113// experimental for faster tiled drawing...
114//#define SK_ENABLE_CLIP_QUICKREJECT
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +0000115
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116//#define SK_TRACE_SAVERESTORE
117
118#ifdef SK_TRACE_SAVERESTORE
119 static int gLayerCounter;
120 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
121 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
122
123 static int gRecCounter;
124 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
125 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
126
127 static int gCanvasCounter;
128 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
129 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
130#else
131 #define inc_layer()
132 #define dec_layer()
133 #define inc_rec()
134 #define dec_rec()
135 #define inc_canvas()
136 #define dec_canvas()
137#endif
138
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000139typedef SkTLazy<SkPaint> SkLazyPaint;
140
reedc83a2972015-07-16 07:40:45 -0700141void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
reed@google.com97af1a62012-08-28 12:19:02 +0000142 if (fSurfaceBase) {
reedc83a2972015-07-16 07:40:45 -0700143 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
144 ? SkSurface::kDiscard_ContentChangeMode
145 : SkSurface::kRetain_ContentChangeMode);
146 }
147}
148
149void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
150 ShaderOverrideOpacity overrideOpacity) {
151 if (fSurfaceBase) {
152 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
153 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
154 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
155 // and therefore we don't care which mode we're in.
156 //
157 if (fSurfaceBase->outstandingImageSnapshot()) {
158 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
159 mode = SkSurface::kDiscard_ContentChangeMode;
160 }
161 }
162 fSurfaceBase->aboutToDraw(mode);
reed@google.com97af1a62012-08-28 12:19:02 +0000163 }
164}
165
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167
reed4a8126e2014-09-22 07:29:03 -0700168static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
169 const uint32_t propFlags = props.flags();
170 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
171 flags &= ~SkPaint::kDither_Flag;
172 }
173 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
174 flags &= ~SkPaint::kAntiAlias_Flag;
175 }
176 return flags;
177}
178
179///////////////////////////////////////////////////////////////////////////////
180
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000181/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 The clip/matrix/proc are fields that reflect the top of the save/restore
183 stack. Whenever the canvas changes, it marks a dirty flag, and then before
184 these are used (assuming we're not on a layer) we rebuild these cache
185 values: they reflect the top of the save stack, but translated and clipped
186 by the device's XY offset and bitmap-bounds.
187*/
188struct DeviceCM {
189 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000190 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000191 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000192 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700193 const SkMatrix* fMatrix;
194 SkMatrix fMatrixStorage;
195 const bool fDeviceIsBitmapDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196
reed96e657d2015-03-10 17:30:07 -0700197 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed86a17e72015-05-14 12:25:22 -0700198 bool conservativeRasterClip, bool deviceIsBitmapDevice)
halcanary96fcdcc2015-08-27 07:41:13 -0700199 : fNext(nullptr)
reedd9544982014-09-09 18:46:22 -0700200 , fClip(conservativeRasterClip)
reed61f501f2015-04-29 08:34:00 -0700201 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700202 {
halcanary96fcdcc2015-08-27 07:41:13 -0700203 if (nullptr != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000205 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206 }
reed@google.com4b226022011-01-11 18:32:13 +0000207 fDevice = device;
halcanary96fcdcc2015-08-27 07:41:13 -0700208 fPaint = paint ? new SkPaint(*paint) : nullptr;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000209 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000211 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700212 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000213 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214 fDevice->unref();
215 }
halcanary385fe4d2015-08-26 13:07:48 -0700216 delete fPaint;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000217 }
reed@google.com4b226022011-01-11 18:32:13 +0000218
mtkleinfeaadee2015-04-08 11:25:48 -0700219 void reset(const SkIRect& bounds) {
220 SkASSERT(!fPaint);
221 SkASSERT(!fNext);
222 SkASSERT(fDevice);
223 fClip.setRect(bounds);
224 }
225
reed@google.com045e62d2011-10-24 12:19:46 +0000226 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
227 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000228 int x = fDevice->getOrigin().x();
229 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230 int width = fDevice->width();
231 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000232
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 if ((x | y) == 0) {
234 fMatrix = &totalMatrix;
235 fClip = totalClip;
236 } else {
237 fMatrixStorage = totalMatrix;
238 fMatrixStorage.postTranslate(SkIntToScalar(-x),
239 SkIntToScalar(-y));
240 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000241
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 totalClip.translate(-x, -y, &fClip);
243 }
244
reed@google.com045e62d2011-10-24 12:19:46 +0000245 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246
247 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000248
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000250 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 SkRegion::kDifference_Op);
252 }
reed@google.com4b226022011-01-11 18:32:13 +0000253
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000254 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
255
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256#ifdef SK_DEBUG
257 if (!fClip.isEmpty()) {
258 SkIRect deviceR;
259 deviceR.set(0, 0, width, height);
260 SkASSERT(deviceR.contains(fClip.getBounds()));
261 }
262#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000263 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264};
265
266/* This is the record we keep for each save/restore level in the stack.
267 Since a level optionally copies the matrix and/or stack, we have pointers
268 for these fields. If the value is copied for this level, the copy is
269 stored in the ...Storage field, and the pointer points to that. If the
270 value is not copied for this level, we ignore ...Storage, and just point
271 at the corresponding value in the previous level in the stack.
272*/
273class SkCanvas::MCRec {
274public:
reed1f836ee2014-07-07 07:49:34 -0700275 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700276 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 /* If there are any layers in the stack, this points to the top-most
278 one that is at or below this level in the stack (so we know what
279 bitmap/device to draw into from this level. This value is NOT
280 reference counted, since the real owner is either our fLayer field,
281 or a previous one in a lower level.)
282 */
reed2ff1fce2014-12-11 07:07:37 -0800283 DeviceCM* fTopLayer;
284 SkRasterClip fRasterClip;
285 SkMatrix fMatrix;
286 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287
reedd9544982014-09-09 18:46:22 -0700288 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
halcanary96fcdcc2015-08-27 07:41:13 -0700289 fFilter = nullptr;
290 fLayer = nullptr;
291 fTopLayer = nullptr;
reed2ff1fce2014-12-11 07:07:37 -0800292 fMatrix.reset();
293 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700294
reedd9544982014-09-09 18:46:22 -0700295 // don't bother initializing fNext
296 inc_rec();
297 }
reed2ff1fce2014-12-11 07:07:37 -0800298 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700299 fFilter = SkSafeRef(prev.fFilter);
halcanary96fcdcc2015-08-27 07:41:13 -0700300 fLayer = nullptr;
reedd9544982014-09-09 18:46:22 -0700301 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800302 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700303
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 // don't bother initializing fNext
305 inc_rec();
306 }
307 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000308 SkSafeUnref(fFilter);
halcanary385fe4d2015-08-26 13:07:48 -0700309 delete fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310 dec_rec();
311 }
mtkleinfeaadee2015-04-08 11:25:48 -0700312
313 void reset(const SkIRect& bounds) {
314 SkASSERT(fLayer);
315 SkASSERT(fDeferredSaveCount == 0);
316
317 fMatrix.reset();
318 fRasterClip.setRect(bounds);
319 fLayer->reset(bounds);
320 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321};
322
323class SkDrawIter : public SkDraw {
324public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000325 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000326 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000327 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328 canvas->updateDeviceCMCache();
329
reed687fa1c2015-04-07 08:00:56 -0700330 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000332 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333 }
reed@google.com4b226022011-01-11 18:32:13 +0000334
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 bool next() {
336 // skip over recs with empty clips
337 if (fSkipEmptyClips) {
338 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
339 fCurrLayer = fCurrLayer->fNext;
340 }
341 }
342
reed@google.comf68c5e22012-02-24 16:38:58 +0000343 const DeviceCM* rec = fCurrLayer;
344 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345
346 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000347 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
348 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700350 if (!fDevice->accessPixels(&fDst)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700351 fDst.reset(fDevice->imageInfo(), nullptr, 0);
reed41e010c2015-06-09 12:16:53 -0700352 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000354 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355
356 fCurrLayer = rec->fNext;
halcanary96fcdcc2015-08-27 07:41:13 -0700357 // fCurrLayer may be nullptr now
reed@android.com199f1082009-06-10 02:12:47 +0000358
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359 return true;
360 }
361 return false;
362 }
reed@google.com4b226022011-01-11 18:32:13 +0000363
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000364 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000365 int getX() const { return fDevice->getOrigin().x(); }
366 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367 const SkMatrix& getMatrix() const { return *fMatrix; }
368 const SkRegion& getClip() const { return *fClip; }
369 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000370
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371private:
372 SkCanvas* fCanvas;
373 const DeviceCM* fCurrLayer;
374 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375 SkBool8 fSkipEmptyClips;
376
377 typedef SkDraw INHERITED;
378};
379
380/////////////////////////////////////////////////////////////////////////////
381
reeddbc3cef2015-04-29 12:18:57 -0700382static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
383 return lazy->isValid() ? lazy->get() : lazy->set(orig);
384}
385
386/**
387 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
halcanary96fcdcc2015-08-27 07:41:13 -0700388 * colorfilter, else return nullptr.
reeddbc3cef2015-04-29 12:18:57 -0700389 */
390static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700391 SkImageFilter* imgf = paint.getImageFilter();
392 if (!imgf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700393 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700394 }
395
396 SkColorFilter* imgCF;
397 if (!imgf->asAColorFilter(&imgCF)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700398 return nullptr;
reeddbc3cef2015-04-29 12:18:57 -0700399 }
400
401 SkColorFilter* paintCF = paint.getColorFilter();
halcanary96fcdcc2015-08-27 07:41:13 -0700402 if (nullptr == paintCF) {
reeddbc3cef2015-04-29 12:18:57 -0700403 // there is no existing paint colorfilter, so we can just return the imagefilter's
404 return imgCF;
405 }
406
407 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
408 // and we need to combine them into a single colorfilter.
409 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
410 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
reeddbc3cef2015-04-29 12:18:57 -0700411}
412
senorblanco87e066e2015-10-28 11:23:36 -0700413/**
414 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
415 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
416 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
417 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
418 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
419 * conservative "effective" bounds based on the settings in the paint... with one exception. This
420 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
421 * deliberately ignored.
422 */
423static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
424 const SkRect& rawBounds,
425 SkRect* storage) {
426 SkPaint tmpUnfiltered(paint);
427 tmpUnfiltered.setImageFilter(nullptr);
428 if (tmpUnfiltered.canComputeFastBounds()) {
429 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
430 } else {
431 return rawBounds;
432 }
433}
434
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435class AutoDrawLooper {
436public:
senorblanco87e066e2015-10-28 11:23:36 -0700437 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
438 // paint. It's used to determine the size of the offscreen layer for filters.
439 // If null, the clip will be used instead.
reed4a8126e2014-09-22 07:29:03 -0700440 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000441 bool skipLayerForImageFilter = false,
senorblanco87e066e2015-10-28 11:23:36 -0700442 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000443 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700445 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000446 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700447 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000448 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449
reeddbc3cef2015-04-29 12:18:57 -0700450 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
451 if (simplifiedCF) {
452 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
453 paint->setColorFilter(simplifiedCF)->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700454 paint->setImageFilter(nullptr);
reeddbc3cef2015-04-29 12:18:57 -0700455 fPaint = paint;
456 }
457
458 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700459 /**
460 * We implement ImageFilters for a given draw by creating a layer, then applying the
461 * imagefilter to the pixels of that layer (its backing surface/image), and then
462 * we call restore() to xfer that layer to the main canvas.
463 *
464 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
465 * 2. Generate the src pixels:
466 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
467 * return (fPaint). We then draw the primitive (using srcover) into a cleared
468 * buffer/surface.
469 * 3. Restore the layer created in #1
470 * The imagefilter is passed the buffer/surface from the layer (now filled with the
471 * src pixels of the primitive). It returns a new "filtered" buffer, which we
472 * draw onto the previous layer using the xfermode from the original paint.
473 */
reed@google.com8926b162012-03-23 15:36:36 +0000474 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700475 tmp.setImageFilter(fPaint->getImageFilter());
476 tmp.setXfermode(fPaint->getXfermode());
senorblanco87e066e2015-10-28 11:23:36 -0700477 SkRect storage;
478 if (rawBounds) {
479 // Make rawBounds include all paint outsets except for those due to image filters.
480 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
481 }
senorblanco87e066e2015-10-28 11:23:36 -0700482 (void)canvas->internalSaveLayer(rawBounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
reed76033be2015-03-14 10:54:31 -0700483 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700484 fTempLayerForImageFilter = true;
485 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000486 }
487
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000488 if (SkDrawLooper* looper = paint.getLooper()) {
489 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
490 looper->contextSize());
491 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000492 fIsSimple = false;
493 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700494 fLooperContext = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000495 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700496 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000497 }
piotaixrb5fae932014-09-24 13:03:30 -0700498
reed4a8126e2014-09-22 07:29:03 -0700499 uint32_t oldFlags = paint.getFlags();
500 fNewPaintFlags = filter_paint_flags(props, oldFlags);
501 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700502 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700503 paint->setFlags(fNewPaintFlags);
504 fPaint = paint;
505 // if we're not simple, doNext() will take care of calling setFlags()
506 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000507 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000508
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700510 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000511 fCanvas->internalRestore();
512 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000513 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000515
reed@google.com4e2b3d32011-04-07 14:18:59 +0000516 const SkPaint& paint() const {
517 SkASSERT(fPaint);
518 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000520
reed@google.com129ec222012-05-15 13:24:09 +0000521 bool next(SkDrawFilter::Type drawType) {
522 if (fDone) {
523 return false;
524 } else if (fIsSimple) {
525 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000526 return !fPaint->nothingToDraw();
527 } else {
528 return this->doNext(drawType);
529 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000530 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000531
reed@android.com8a1c16f2008-12-17 15:59:43 +0000532private:
reeddbc3cef2015-04-29 12:18:57 -0700533 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
534 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000535 SkCanvas* fCanvas;
536 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000537 SkDrawFilter* fFilter;
538 const SkPaint* fPaint;
539 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700540 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700541 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000542 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000543 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000544 SkDrawLooper::Context* fLooperContext;
545 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000546
547 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000548};
549
reed@google.com129ec222012-05-15 13:24:09 +0000550bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700551 fPaint = nullptr;
reed@google.com129ec222012-05-15 13:24:09 +0000552 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700553 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000554
reeddbc3cef2015-04-29 12:18:57 -0700555 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
556 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700557 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000558
reed5c476fb2015-04-20 08:04:21 -0700559 if (fTempLayerForImageFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700560 paint->setImageFilter(nullptr);
561 paint->setXfermode(nullptr);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000562 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000563
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000564 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000565 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000566 return false;
567 }
568 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000569 if (!fFilter->filter(paint, drawType)) {
570 fDone = true;
571 return false;
572 }
halcanary96fcdcc2015-08-27 07:41:13 -0700573 if (nullptr == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000574 // no looper means we only draw once
575 fDone = true;
576 }
577 }
578 fPaint = paint;
579
580 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000581 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000582 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000583 }
584
585 // call this after any possible paint modifiers
586 if (fPaint->nothingToDraw()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700587 fPaint = nullptr;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000588 return false;
589 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000590 return true;
591}
592
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593////////// macros to place around the internal draw calls //////////////////
594
reed@google.com8926b162012-03-23 15:36:36 +0000595#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000596 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700597 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000598 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000599 SkDrawIter iter(this);
600
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000601#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000602 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700603 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000604 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000605 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000606
reedc83a2972015-07-16 07:40:45 -0700607#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
608 this->predrawNotify(bounds, &paint, auxOpaque); \
609 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
610 while (looper.next(type)) { \
611 SkDrawIter iter(this);
612
reed@google.com4e2b3d32011-04-07 14:18:59 +0000613#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614
615////////////////////////////////////////////////////////////////////////////
616
mtkleinfeaadee2015-04-08 11:25:48 -0700617void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
618 this->restoreToCount(1);
619 fCachedLocalClipBounds.setEmpty();
620 fCachedLocalClipBoundsDirty = true;
621 fClipStack->reset();
622 fMCRec->reset(bounds);
623
624 // We're peering through a lot of structs here. Only at this scope do we
625 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
626 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
627}
628
reedd9544982014-09-09 18:46:22 -0700629SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
reed42b73eb2015-11-20 13:42:42 -0800630 if (device && device->forceConservativeRasterClip()) {
631 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
632 }
633 // Since init() is only called once by our constructors, it is safe to perform this
634 // const-cast.
635 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
636
reed@google.comc0784db2013-12-13 21:16:12 +0000637 fCachedLocalClipBounds.setEmpty();
638 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000639 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000640 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700641 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800642 fSaveCount = 1;
halcanary96fcdcc2015-08-27 07:41:13 -0700643 fMetaData = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644
halcanary385fe4d2015-08-26 13:07:48 -0700645 fClipStack.reset(new SkClipStack);
reed687fa1c2015-04-07 08:00:56 -0700646
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700648 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649
reeda499f902015-05-01 09:34:31 -0700650 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
651 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
halcanary96fcdcc2015-08-27 07:41:13 -0700652 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700653
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000655
halcanary96fcdcc2015-08-27 07:41:13 -0700656 fSurfaceBase = nullptr;
reed@android.comf2b98d62010-12-20 18:26:13 +0000657
reedf92c8662014-08-18 08:02:43 -0700658 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700659 // The root device and the canvas should always have the same pixel geometry
660 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reedf92c8662014-08-18 08:02:43 -0700661 device->onAttachToCanvas(this);
662 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800663 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700664 }
665 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666}
667
reed@google.comcde92112011-07-06 20:00:52 +0000668SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000669 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700670 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800671 , fConservativeRasterClip(false)
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))
reed42b73eb2015-11-20 13:42:42 -0800700 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000701{
702 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700703
halcanary385fe4d2015-08-26 13:07:48 -0700704 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
705 kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700706}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000707
reed78e27682014-11-19 08:04:34 -0800708SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700709 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700710 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800711 , fConservativeRasterClip(false)
reedd9544982014-09-09 18:46:22 -0700712{
713 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700714
halcanary385fe4d2015-08-26 13:07:48 -0700715 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700716}
717
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000718SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000719 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700720 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800721 , fConservativeRasterClip(false)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000722{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000723 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700724
reedd9544982014-09-09 18:46:22 -0700725 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000726}
727
robertphillipsfcf78292015-06-19 11:49:52 -0700728SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
729 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700730 , fProps(device->surfaceProps())
reed42b73eb2015-11-20 13:42:42 -0800731 , fConservativeRasterClip(false)
robertphillipsfcf78292015-06-19 11:49:52 -0700732{
733 inc_canvas();
734
735 this->init(device, flags);
736}
737
reed4a8126e2014-09-22 07:29:03 -0700738SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700739 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700740 , fProps(props)
reed42b73eb2015-11-20 13:42:42 -0800741 , fConservativeRasterClip(false)
reed3716fd02014-09-21 09:39:55 -0700742{
743 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700744
halcanary385fe4d2015-08-26 13:07:48 -0700745 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700746 this->init(device, kDefault_InitFlags);
747}
reed29c857d2014-09-21 10:25:07 -0700748
reed4a8126e2014-09-22 07:29:03 -0700749SkCanvas::SkCanvas(const SkBitmap& bitmap)
750 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
751 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reed42b73eb2015-11-20 13:42:42 -0800752 , fConservativeRasterClip(false)
reed4a8126e2014-09-22 07:29:03 -0700753{
754 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700755
halcanary385fe4d2015-08-26 13:07:48 -0700756 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
reed4a8126e2014-09-22 07:29:03 -0700757 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758}
759
760SkCanvas::~SkCanvas() {
761 // free up the contents of our deque
762 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000763
reed@android.com8a1c16f2008-12-17 15:59:43 +0000764 this->internalRestore(); // restore the last, since we're going away
765
halcanary385fe4d2015-08-26 13:07:48 -0700766 delete fMetaData;
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000767
reed@android.com8a1c16f2008-12-17 15:59:43 +0000768 dec_canvas();
769}
770
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771SkDrawFilter* SkCanvas::getDrawFilter() const {
772 return fMCRec->fFilter;
773}
774
775SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700776 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000777 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
778 return filter;
779}
780
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000781SkMetaData& SkCanvas::getMetaData() {
782 // metadata users are rare, so we lazily allocate it. If that changes we
783 // can decide to just make it a field in the device (rather than a ptr)
halcanary96fcdcc2015-08-27 07:41:13 -0700784 if (nullptr == fMetaData) {
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000785 fMetaData = new SkMetaData;
786 }
787 return *fMetaData;
788}
789
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790///////////////////////////////////////////////////////////////////////////////
791
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000792void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000793 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000794 if (device) {
795 device->flush();
796 }
797}
798
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000799SkISize SkCanvas::getTopLayerSize() const {
800 SkBaseDevice* d = this->getTopDevice();
801 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
802}
803
804SkIPoint SkCanvas::getTopLayerOrigin() const {
805 SkBaseDevice* d = this->getTopDevice();
806 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
807}
808
809SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000810 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000811 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
812}
813
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000814SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000815 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000816 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817 SkASSERT(rec && rec->fLayer);
818 return rec->fLayer->fDevice;
819}
820
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000821SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000822 if (updateMatrixClip) {
823 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
824 }
reed@google.com9266fed2011-03-30 00:18:03 +0000825 return fMCRec->fTopLayer->fDevice;
826}
827
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000828bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
829 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
830 return false;
831 }
832
833 bool weAllocated = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700834 if (nullptr == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700835 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000836 return false;
837 }
838 weAllocated = true;
839 }
840
reedcf01e312015-05-23 19:14:51 -0700841 SkAutoPixmapUnlock unlocker;
842 if (bitmap->requestLock(&unlocker)) {
843 const SkPixmap& pm = unlocker.pixmap();
844 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
845 return true;
846 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000847 }
848
849 if (weAllocated) {
halcanary96fcdcc2015-08-27 07:41:13 -0700850 bitmap->setPixelRef(nullptr);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000851 }
852 return false;
853}
reed@google.com51df9e32010-12-23 19:29:18 +0000854
bsalomon@google.comc6980972011-11-02 19:57:21 +0000855bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000856 SkIRect r = srcRect;
857 const SkISize size = this->getBaseLayerSize();
858 if (!r.intersect(0, 0, size.width(), size.height())) {
859 bitmap->reset();
860 return false;
861 }
862
reed84825042014-09-02 12:50:45 -0700863 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000864 // bitmap will already be reset.
865 return false;
866 }
867 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
868 bitmap->reset();
869 return false;
870 }
871 return true;
872}
873
reed96472de2014-12-10 09:53:42 -0800874bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000875 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000876 if (!device) {
877 return false;
878 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000879 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800880
reed96472de2014-12-10 09:53:42 -0800881 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
882 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000883 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000884 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000885
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000886 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800887 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000888}
889
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000890bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
891 if (bitmap.getTexture()) {
892 return false;
893 }
reedcf01e312015-05-23 19:14:51 -0700894
895 SkAutoPixmapUnlock unlocker;
896 if (bitmap.requestLock(&unlocker)) {
897 const SkPixmap& pm = unlocker.pixmap();
898 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000899 }
900 return false;
901}
902
903bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
904 int x, int y) {
905 switch (origInfo.colorType()) {
906 case kUnknown_SkColorType:
907 case kIndex_8_SkColorType:
908 return false;
909 default:
910 break;
911 }
halcanary96fcdcc2015-08-27 07:41:13 -0700912 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000913 return false;
914 }
915
916 const SkISize size = this->getBaseLayerSize();
917 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
918 if (!target.intersect(0, 0, size.width(), size.height())) {
919 return false;
920 }
921
922 SkBaseDevice* device = this->getDevice();
923 if (!device) {
924 return false;
925 }
926
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000927 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700928 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000929
930 // if x or y are negative, then we have to adjust pixels
931 if (x > 0) {
932 x = 0;
933 }
934 if (y > 0) {
935 y = 0;
936 }
937 // here x,y are either 0 or negative
938 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
939
reed4af35f32014-06-27 17:47:49 -0700940 // Tell our owning surface to bump its generation ID
reedc83a2972015-07-16 07:40:45 -0700941 const bool completeOverwrite = info.dimensions() == size;
942 this->predrawNotify(completeOverwrite);
reed4af35f32014-06-27 17:47:49 -0700943
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000944 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000945 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000946}
reed@google.com51df9e32010-12-23 19:29:18 +0000947
junov@google.com4370aed2012-01-18 16:21:08 +0000948SkCanvas* SkCanvas::canvasForDrawIter() {
949 return this;
950}
951
reed@android.com8a1c16f2008-12-17 15:59:43 +0000952//////////////////////////////////////////////////////////////////////////////
953
reed@android.com8a1c16f2008-12-17 15:59:43 +0000954void SkCanvas::updateDeviceCMCache() {
955 if (fDeviceCMDirty) {
956 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700957 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000958 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000959
halcanary96fcdcc2015-08-27 07:41:13 -0700960 if (nullptr == layer->fNext) { // only one layer
961 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000963 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 do {
reed687fa1c2015-04-07 08:00:56 -0700965 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
halcanary96fcdcc2015-08-27 07:41:13 -0700966 } while ((layer = layer->fNext) != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967 }
968 fDeviceCMDirty = false;
969 }
970}
971
reed@android.com8a1c16f2008-12-17 15:59:43 +0000972///////////////////////////////////////////////////////////////////////////////
973
reed2ff1fce2014-12-11 07:07:37 -0800974void SkCanvas::checkForDeferredSave() {
975 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800976 this->doSave();
977 }
978}
979
reedf0090cb2014-11-26 08:55:51 -0800980int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800981#ifdef SK_DEBUG
982 int count = 0;
983 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
984 for (;;) {
985 const MCRec* rec = (const MCRec*)iter.next();
986 if (!rec) {
987 break;
988 }
989 count += 1 + rec->fDeferredSaveCount;
990 }
991 SkASSERT(count == fSaveCount);
992#endif
993 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800994}
995
996int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800997 fSaveCount += 1;
998 fMCRec->fDeferredSaveCount += 1;
999 return this->getSaveCount() - 1; // return our prev value
1000}
1001
1002void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -08001003 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -07001004
1005 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1006 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001007 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -08001008}
1009
1010void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -08001011 if (fMCRec->fDeferredSaveCount > 0) {
1012 SkASSERT(fSaveCount > 1);
1013 fSaveCount -= 1;
1014 fMCRec->fDeferredSaveCount -= 1;
1015 } else {
1016 // check for underflow
1017 if (fMCStack.count() > 1) {
1018 this->willRestore();
1019 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -07001020 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -08001021 this->internalRestore();
1022 this->didRestore();
1023 }
reedf0090cb2014-11-26 08:55:51 -08001024 }
1025}
1026
1027void SkCanvas::restoreToCount(int count) {
1028 // sanity check
1029 if (count < 1) {
1030 count = 1;
1031 }
mtkleinf0f14112014-12-12 08:46:25 -08001032
reedf0090cb2014-11-26 08:55:51 -08001033 int n = this->getSaveCount() - count;
1034 for (int i = 0; i < n; ++i) {
1035 this->restore();
1036 }
1037}
1038
reed2ff1fce2014-12-11 07:07:37 -08001039void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001040 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -07001041 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +00001042 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +00001043
reed687fa1c2015-04-07 08:00:56 -07001044 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001045}
1046
reed@android.com8a1c16f2008-12-17 15:59:43 +00001047static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +00001048#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +00001049 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +00001050#else
1051 return true;
1052#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001053}
1054
junov@chromium.orga907ac32012-02-24 21:54:07 +00001055bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -07001056 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001057 SkIRect clipBounds;
1058 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +00001059 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +00001060 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001061
reed96e657d2015-03-10 17:30:07 -07001062 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1063
senorblanco87e066e2015-10-28 11:23:36 -07001064// This is a temporary hack, until individual filters can do their own
1065// bloating, when this will be removed.
1066#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
1067 SkRect storage;
1068#endif
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001069 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -07001070 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco87e066e2015-10-28 11:23:36 -07001071#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
1072 if (bounds && imageFilter->canComputeFastBounds()) {
1073 imageFilter->computeFastBounds(*bounds, &storage);
1074 bounds = &storage;
1075 } else {
1076 bounds = nullptr;
1077 }
1078#endif
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001079 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001080 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -07001081 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001082 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +00001083
reed96e657d2015-03-10 17:30:07 -07001084 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001085 r.roundOut(&ir);
1086 // early exit if the layer's bounds are clipped out
1087 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001088 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -07001089 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001090 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001091 }
junov@chromium.orga907ac32012-02-24 21:54:07 +00001092 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093 }
1094 } else { // no user bounds, so just use the clip
1095 ir = clipBounds;
1096 }
reed180aec42015-03-11 10:39:04 -07001097 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +00001099 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -07001100 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -07001101 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -07001102 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -07001103 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +00001104 }
1105
1106 if (intersection) {
1107 *intersection = ir;
1108 }
1109 return true;
1110}
1111
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001112int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -08001113 if (gIgnoreSaveLayerBounds) {
halcanary96fcdcc2015-08-27 07:41:13 -07001114 bounds = nullptr;
reedd990e2f2014-12-22 11:58:30 -08001115 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001116 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -07001117 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -07001118 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -08001119 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001120}
1121
reed2ff1fce2014-12-11 07:07:37 -08001122int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -08001123 if (gIgnoreSaveLayerBounds) {
halcanary96fcdcc2015-08-27 07:41:13 -07001124 bounds = nullptr;
reedd990e2f2014-12-22 11:58:30 -08001125 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001126 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -07001127 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -07001128 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -08001129 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +00001130}
1131
reed2ff1fce2014-12-11 07:07:37 -08001132void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -07001133 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +00001134#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +00001135 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001136#endif
1137
junov@chromium.orga907ac32012-02-24 21:54:07 +00001138 // do this before we create the layer. We don't call the public save() since
1139 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001140 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001141
1142 fDeviceCMDirty = true;
1143
1144 SkIRect ir;
halcanary96fcdcc2015-08-27 07:41:13 -07001145 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : nullptr)) {
reed2ff1fce2014-12-11 07:07:37 -08001146 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147 }
1148
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001149 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1150 // the clipRectBounds() call above?
1151 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001152 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001153 }
1154
reed76033be2015-03-14 10:54:31 -07001155 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001156 SkPixelGeometry geo = fProps.pixelGeometry();
1157 if (paint) {
reed76033be2015-03-14 10:54:31 -07001158 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001159 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001160 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001161 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001162 }
1163 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001164 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1165 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001166
reedb2db8982014-11-13 12:41:02 -08001167 SkBaseDevice* device = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001168 if (nullptr == device) {
reedb2db8982014-11-13 12:41:02 -08001169 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001170 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001171 }
reedb2db8982014-11-13 12:41:02 -08001172
reed61f501f2015-04-29 08:34:00 -07001173 bool forceSpriteOnRestore = false;
1174 {
reeddaa57bf2015-05-15 10:39:17 -07001175 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed61f501f2015-04-29 08:34:00 -07001176 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo);
1177 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001178 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001179 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001180 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1181 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
halcanary96fcdcc2015-08-27 07:41:13 -07001182 if (nullptr == newDev) {
reed61f501f2015-04-29 08:34:00 -07001183 SkErrorInternals::SetError(kInternalError_SkError,
1184 "Unable to create device for layer.");
1185 return;
1186 }
1187 forceSpriteOnRestore = true;
1188 }
1189 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001190 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001191
reed@google.com6f8f2922011-03-04 22:27:10 +00001192 device->setOrigin(ir.fLeft, ir.fTop);
halcanary385fe4d2015-08-26 13:07:48 -07001193 DeviceCM* layer =
1194 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001195 device->unref();
1196
1197 layer->fNext = fMCRec->fTopLayer;
1198 fMCRec->fLayer = layer;
1199 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200}
1201
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001202int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1203 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1204}
1205
reed@android.com8a1c16f2008-12-17 15:59:43 +00001206int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1207 SaveFlags flags) {
1208 if (0xFF == alpha) {
halcanary96fcdcc2015-08-27 07:41:13 -07001209 return this->saveLayer(bounds, nullptr, flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210 } else {
1211 SkPaint tmpPaint;
1212 tmpPaint.setAlpha(alpha);
1213 return this->saveLayer(bounds, &tmpPaint, flags);
1214 }
1215}
1216
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217void SkCanvas::internalRestore() {
1218 SkASSERT(fMCStack.count() != 0);
1219
1220 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001221 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222
reed687fa1c2015-04-07 08:00:56 -07001223 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001224
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001225 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226 DeviceCM* layer = fMCRec->fLayer; // may be null
1227 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
halcanary96fcdcc2015-08-27 07:41:13 -07001228 fMCRec->fLayer = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001229
1230 // now do the normal restore()
1231 fMCRec->~MCRec(); // balanced in save()
1232 fMCStack.pop_back();
1233 fMCRec = (MCRec*)fMCStack.back();
1234
1235 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1236 since if we're being recorded, we don't want to record this (the
1237 recorder will have already recorded the restore).
1238 */
bsalomon49f085d2014-09-05 13:34:00 -07001239 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001241 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001242 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001243 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001244 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245 fDeviceCMDirty = true;
halcanary385fe4d2015-08-26 13:07:48 -07001246 delete layer;
reedb679ca82015-04-07 04:40:48 -07001247 } else {
1248 // we're at the root
reeda499f902015-05-01 09:34:31 -07001249 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001250 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001251 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001252 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001253}
1254
reed4a8126e2014-09-22 07:29:03 -07001255SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
halcanary96fcdcc2015-08-27 07:41:13 -07001256 if (nullptr == props) {
reed4a8126e2014-09-22 07:29:03 -07001257 props = &fProps;
1258 }
1259 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001260}
1261
reed4a8126e2014-09-22 07:29:03 -07001262SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001263 SkBaseDevice* dev = this->getDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001264 return dev ? dev->newSurface(info, props) : nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +00001265}
1266
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001267SkImageInfo SkCanvas::imageInfo() const {
1268 SkBaseDevice* dev = this->getDevice();
1269 if (dev) {
1270 return dev->imageInfo();
1271 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001272 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001273 }
1274}
1275
1276const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001277 SkPixmap pmap;
1278 if (!this->onPeekPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001279 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001280 }
1281 if (info) {
1282 *info = pmap.info();
1283 }
1284 if (rowBytes) {
1285 *rowBytes = pmap.rowBytes();
1286 }
1287 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001288}
1289
reed884e97c2015-05-26 11:31:54 -07001290bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001291 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001292 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001293}
1294
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001295void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001296 SkPixmap pmap;
1297 if (!this->onAccessTopLayerPixels(&pmap)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001298 return nullptr;
reed884e97c2015-05-26 11:31:54 -07001299 }
1300 if (info) {
1301 *info = pmap.info();
1302 }
1303 if (rowBytes) {
1304 *rowBytes = pmap.rowBytes();
1305 }
1306 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001307 *origin = this->getTopDevice(false)->getOrigin();
1308 }
reed884e97c2015-05-26 11:31:54 -07001309 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001310}
1311
reed884e97c2015-05-26 11:31:54 -07001312bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001313 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001314 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001315}
1316
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001317SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1318 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
halcanary96fcdcc2015-08-27 07:41:13 -07001319 if (nullptr == fAddr) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001320 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001321 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001322 return; // failure, fAddr is nullptr
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001323 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001324 if (!canvas->readPixels(&fBitmap, 0, 0)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001325 return; // failure, fAddr is nullptr
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001326 }
1327 fAddr = fBitmap.getPixels();
1328 fRowBytes = fBitmap.rowBytes();
1329 }
1330 SkASSERT(fAddr); // success
1331}
1332
1333bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1334 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001335 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001336 } else {
1337 bitmap->reset();
1338 return false;
1339 }
1340}
1341
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342/////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001344void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001345 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001347 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001348 paint = &tmp;
1349 }
reed@google.com4b226022011-01-11 18:32:13 +00001350
reed@google.com8926b162012-03-23 15:36:36 +00001351 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001352 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001353 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001354 paint = &looper.paint();
1355 SkImageFilter* filter = paint->getImageFilter();
1356 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001357 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001358 SkImageFilter::DeviceProxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001359 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001360 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001361 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001362 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001363 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001364 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001365 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
reedc9b5f8b2015-10-22 13:20:20 -07001366 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(),
1367 SkImageFilter::kApprox_SizeConstraint);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001368 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001369 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001370 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001371 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1372 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001373 }
reed61f501f2015-04-29 08:34:00 -07001374 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001375 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001376 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001377 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001378 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001379 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001380 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001381 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001382}
1383
reed41af9662015-01-05 07:49:08 -08001384void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001385 if (gTreatSpriteAsBitmap) {
1386 this->save();
1387 this->resetMatrix();
1388 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1389 this->restore();
1390 return;
1391 }
1392
danakj9881d632014-11-26 12:41:06 -08001393 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001394 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001395 return;
1396 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001397 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001398
reed@google.com8926b162012-03-23 15:36:36 +00001399 SkPaint tmp;
halcanary96fcdcc2015-08-27 07:41:13 -07001400 if (nullptr == paint) {
reed@google.com8926b162012-03-23 15:36:36 +00001401 paint = &tmp;
1402 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001403
reed@google.com8926b162012-03-23 15:36:36 +00001404 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001405
reed@google.com8926b162012-03-23 15:36:36 +00001406 while (iter.next()) {
1407 paint = &looper.paint();
1408 SkImageFilter* filter = paint->getImageFilter();
1409 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1410 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
reed88d064d2015-10-12 11:30:02 -07001411 SkImageFilter::DeviceProxy proxy(iter.fDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001412 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001413 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001414 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001415 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001416 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001417 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
reedc9b5f8b2015-10-22 13:20:20 -07001418 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(),
1419 SkImageFilter::kApprox_SizeConstraint);
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001420 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001421 SkPaint tmpUnfiltered(*paint);
halcanary96fcdcc2015-08-27 07:41:13 -07001422 tmpUnfiltered.setImageFilter(nullptr);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001423 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001424 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001425 }
1426 } else {
1427 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1428 }
1429 }
1430 LOOPER_END
1431}
1432
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001434void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001435 SkMatrix m;
1436 m.setTranslate(dx, dy);
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::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001441 SkMatrix m;
1442 m.setScale(sx, sy);
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::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001447 SkMatrix m;
1448 m.setRotate(degrees);
1449 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450}
1451
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001452void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001453 SkMatrix m;
1454 m.setSkew(sx, sy);
1455 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001456}
1457
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001458void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001459 if (matrix.isIdentity()) {
1460 return;
1461 }
1462
reed2ff1fce2014-12-11 07:07:37 -08001463 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001464 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001465 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001466 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001467
1468 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001469}
1470
reed86a17e72015-05-14 12:25:22 -07001471void SkCanvas::setMatrix(const SkMatrix& matrix) {
1472 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001473 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001474 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001475 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001476 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001477}
1478
reed@android.com8a1c16f2008-12-17 15:59:43 +00001479void SkCanvas::resetMatrix() {
1480 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001481
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482 matrix.reset();
1483 this->setMatrix(matrix);
1484}
1485
1486//////////////////////////////////////////////////////////////////////////////
1487
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001488void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001489 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001490 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1491 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001492}
1493
1494void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001495#ifdef SK_ENABLE_CLIP_QUICKREJECT
1496 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001497 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001498 return false;
1499 }
1500
reed@google.com3b3e8952012-08-16 20:53:31 +00001501 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001502 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001503 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001504
reed687fa1c2015-04-07 08:00:56 -07001505 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001506 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001507 }
1508 }
1509#endif
1510
bsalomonac8cabd2015-11-20 18:53:07 -08001511 if (!fAllowSoftClip) {
1512 edgeStyle = kHard_ClipEdgeStyle;
1513 }
reed90ba0952015-11-20 13:42:47 -08001514
reedc64eff52015-11-21 12:39:45 -08001515 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1516 SkRect devR;
1517 if (rectStaysRect) {
1518 fMCRec->fMatrix.mapRect(&devR, rect);
1519 }
bsalomonac8cabd2015-11-20 18:53:07 -08001520
reedc64eff52015-11-21 12:39:45 -08001521 // Check if we can quick-accept the clip call (and do nothing)
1522 //
1523 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1524 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1525 // might allow lazy save/restores to eliminate entire save/restore blocks.
1526 //
1527 if (SkRegion::kIntersect_Op == op &&
1528 kHard_ClipEdgeStyle == edgeStyle
1529 && rectStaysRect)
1530 {
1531 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1532#if 0
1533 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1534 rect.left(), rect.top(), rect.right(), rect.bottom());
1535#endif
1536 return;
1537 }
1538 }
1539
1540 AutoValidateClip avc(this);
1541
1542 fDeviceCMDirty = true;
1543 fCachedLocalClipBoundsDirty = true;
1544
1545 if (rectStaysRect) {
1546 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1547 fClipStack->clipDevRect(devR, op, isAA);
1548 fMCRec->fRasterClip.op(devR, this->getBaseLayerSize(), op, isAA);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001549 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001550 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001551 // and clip against that, since it can handle any matrix. However, to
1552 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1553 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001554 SkPath path;
1555
1556 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001557 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001558 }
1559}
1560
reed73e714e2014-09-04 09:02:23 -07001561static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1562 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001563 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001564}
1565
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001566void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001567 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001568 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001569 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001570 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1571 } else {
1572 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001573 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001574}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001575
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001576void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001577 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001578 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001579 AutoValidateClip avc(this);
1580
1581 fDeviceCMDirty = true;
1582 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001583 if (!fAllowSoftClip) {
1584 edgeStyle = kHard_ClipEdgeStyle;
1585 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001586
reed687fa1c2015-04-07 08:00:56 -07001587 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001588
1589 SkPath devPath;
1590 devPath.addRRect(transformedRRect);
1591
reed73e714e2014-09-04 09:02:23 -07001592 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001593 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001594 }
1595
1596 SkPath path;
1597 path.addRRect(rrect);
1598 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001599 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001600}
1601
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001602void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001603 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001604 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1605 SkRect r;
1606 if (!path.isInverseFillType() && path.isRect(&r)) {
1607 this->onClipRect(r, op, edgeStyle);
1608 } else {
1609 this->onClipPath(path, op, edgeStyle);
1610 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001611}
1612
1613void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001614#ifdef SK_ENABLE_CLIP_QUICKREJECT
1615 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001616 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001617 return false;
1618 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001619
reed@google.com3b3e8952012-08-16 20:53:31 +00001620 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001621 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001622 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001623
reed687fa1c2015-04-07 08:00:56 -07001624 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001625 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001626 }
1627 }
1628#endif
1629
reed@google.com5c3d1472011-02-22 19:12:23 +00001630 AutoValidateClip avc(this);
1631
reed@android.com8a1c16f2008-12-17 15:59:43 +00001632 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001633 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001634 if (!fAllowSoftClip) {
1635 edgeStyle = kHard_ClipEdgeStyle;
1636 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001637
1638 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001639 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001640
reed@google.comfe701122011-11-08 19:41:23 +00001641 // Check if the transfomation, or the original path itself
1642 // made us empty. Note this can also happen if we contained NaN
1643 // values. computing the bounds detects this, and will set our
1644 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1645 if (devPath.getBounds().isEmpty()) {
1646 // resetting the path will remove any NaN or other wanky values
1647 // that might upset our scan converter.
1648 devPath.reset();
1649 }
1650
reed@google.com5c3d1472011-02-22 19:12:23 +00001651 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001652 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001653
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001654 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001655 bool clipIsAA = getClipStack()->asPath(&devPath);
1656 if (clipIsAA) {
1657 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001658 }
fmalita1a481fe2015-02-04 07:39:34 -08001659
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001660 op = SkRegion::kReplace_Op;
1661 }
1662
reed73e714e2014-09-04 09:02:23 -07001663 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664}
1665
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001666void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001667 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001668 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001669}
1670
1671void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001672 AutoValidateClip avc(this);
1673
reed@android.com8a1c16f2008-12-17 15:59:43 +00001674 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001675 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001676
reed@google.com5c3d1472011-02-22 19:12:23 +00001677 // todo: signal fClipStack that we have a region, and therefore (I guess)
1678 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001679 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001680
reed1f836ee2014-07-07 07:49:34 -07001681 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001682}
1683
reed@google.com819c9212011-02-23 18:56:55 +00001684#ifdef SK_DEBUG
1685void SkCanvas::validateClip() const {
1686 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001687 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001688 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001689 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001690 return;
1691 }
1692
reed@google.com819c9212011-02-23 18:56:55 +00001693 SkIRect ir;
1694 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001695 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001696
reed687fa1c2015-04-07 08:00:56 -07001697 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001698 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001699 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001700 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001701 case SkClipStack::Element::kRect_Type:
1702 element->getRect().round(&ir);
1703 tmpClip.op(ir, element->getOp());
1704 break;
1705 case SkClipStack::Element::kEmpty_Type:
1706 tmpClip.setEmpty();
1707 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001708 default: {
1709 SkPath path;
1710 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001711 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001712 break;
1713 }
reed@google.com819c9212011-02-23 18:56:55 +00001714 }
1715 }
reed@google.com819c9212011-02-23 18:56:55 +00001716}
1717#endif
1718
reed@google.com90c07ea2012-04-13 13:50:27 +00001719void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001720 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001721 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001722
halcanary96fcdcc2015-08-27 07:41:13 -07001723 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001724 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001725 }
1726}
1727
reed@google.com5c3d1472011-02-22 19:12:23 +00001728///////////////////////////////////////////////////////////////////////////////
1729
reed@google.com754de5f2014-02-24 19:38:20 +00001730bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001731 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001732}
1733
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001734bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001735 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001736}
1737
reed@google.com3b3e8952012-08-16 20:53:31 +00001738bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001739 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001740 return true;
1741
reed1f836ee2014-07-07 07:49:34 -07001742 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001743 return true;
1744 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001745
reed1f836ee2014-07-07 07:49:34 -07001746 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001747 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001748 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001749 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001750 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001751 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001752
reed@android.coma380ae42009-07-21 01:17:02 +00001753 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001754 // TODO: should we use | instead, or compare all 4 at once?
1755 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001756 return true;
1757 }
reed@google.comc0784db2013-12-13 21:16:12 +00001758 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001759 return true;
1760 }
1761 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001762 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001763}
1764
reed@google.com3b3e8952012-08-16 20:53:31 +00001765bool SkCanvas::quickReject(const SkPath& path) const {
1766 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001767}
1768
reed@google.com3b3e8952012-08-16 20:53:31 +00001769bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001770 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001771 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001772 return false;
1773 }
1774
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001775 SkMatrix inverse;
1776 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001777 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001778 if (bounds) {
1779 bounds->setEmpty();
1780 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001781 return false;
1782 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001783
bsalomon49f085d2014-09-05 13:34:00 -07001784 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001785 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001786 // adjust it outwards in case we are antialiasing
1787 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001788
reed@google.com8f4d2302013-12-17 16:44:46 +00001789 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1790 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001791 inverse.mapRect(bounds, r);
1792 }
1793 return true;
1794}
1795
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001796bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001797 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001798 if (clip.isEmpty()) {
1799 if (bounds) {
1800 bounds->setEmpty();
1801 }
1802 return false;
1803 }
1804
bsalomon49f085d2014-09-05 13:34:00 -07001805 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001806 *bounds = clip.getBounds();
1807 }
1808 return true;
1809}
1810
reed@android.com8a1c16f2008-12-17 15:59:43 +00001811const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001812 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001813}
1814
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001815const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001816 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001817}
1818
reed@google.com9c135db2014-03-12 18:28:35 +00001819GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1820 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001821 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001822}
1823
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001824GrContext* SkCanvas::getGrContext() {
1825#if SK_SUPPORT_GPU
1826 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001827 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001828 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001829 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001830 return renderTarget->getContext();
1831 }
1832 }
1833#endif
1834
halcanary96fcdcc2015-08-27 07:41:13 -07001835 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001836
1837}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001838
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001839void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1840 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001841 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001842 if (outer.isEmpty()) {
1843 return;
1844 }
1845 if (inner.isEmpty()) {
1846 this->drawRRect(outer, paint);
1847 return;
1848 }
1849
1850 // We don't have this method (yet), but technically this is what we should
1851 // be able to assert...
1852 // SkASSERT(outer.contains(inner));
1853 //
1854 // For now at least check for containment of bounds
1855 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1856
1857 this->onDrawDRRect(outer, inner, paint);
1858}
1859
reed41af9662015-01-05 07:49:08 -08001860// These need to stop being virtual -- clients need to override the onDraw... versions
1861
1862void SkCanvas::drawPaint(const SkPaint& paint) {
1863 this->onDrawPaint(paint);
1864}
1865
1866void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1867 this->onDrawRect(r, paint);
1868}
1869
1870void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1871 this->onDrawOval(r, paint);
1872}
1873
1874void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1875 this->onDrawRRect(rrect, paint);
1876}
1877
1878void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1879 this->onDrawPoints(mode, count, pts, paint);
1880}
1881
1882void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1883 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1884 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1885 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1886 indices, indexCount, paint);
1887}
1888
1889void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1890 this->onDrawPath(path, paint);
1891}
1892
reeda85d4d02015-05-06 12:56:48 -07001893void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1894 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001895}
1896
reede47829b2015-08-06 10:02:53 -07001897void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1898 const SkPaint* paint, SrcRectConstraint constraint) {
1899 if (dst.isEmpty() || src.isEmpty()) {
1900 return;
1901 }
1902 this->onDrawImageRect(image, &src, dst, paint, constraint);
1903}
reed41af9662015-01-05 07:49:08 -08001904
reed84984ef2015-07-17 07:09:43 -07001905void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1906 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001907 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001908}
1909
reede47829b2015-08-06 10:02:53 -07001910void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1911 SrcRectConstraint constraint) {
1912 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1913 constraint);
1914}
reede47829b2015-08-06 10:02:53 -07001915
reed4c21dc52015-06-25 12:32:03 -07001916void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1917 const SkPaint* paint) {
1918 if (dst.isEmpty()) {
1919 return;
1920 }
1921 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001922 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001923 }
1924 this->onDrawImageNine(image, center, dst, paint);
1925}
1926
reed41af9662015-01-05 07:49:08 -08001927void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001928 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001929 return;
1930 }
reed41af9662015-01-05 07:49:08 -08001931 this->onDrawBitmap(bitmap, dx, dy, paint);
1932}
1933
reede47829b2015-08-06 10:02:53 -07001934void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001935 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001936 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001937 return;
1938 }
reede47829b2015-08-06 10:02:53 -07001939 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001940}
1941
reed84984ef2015-07-17 07:09:43 -07001942void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1943 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001944 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001945}
1946
reede47829b2015-08-06 10:02:53 -07001947void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1948 SrcRectConstraint constraint) {
1949 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1950 constraint);
1951}
reede47829b2015-08-06 10:02:53 -07001952
reed41af9662015-01-05 07:49:08 -08001953void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1954 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001955 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001956 return;
1957 }
reed4c21dc52015-06-25 12:32:03 -07001958 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001959 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001960 }
reed41af9662015-01-05 07:49:08 -08001961 this->onDrawBitmapNine(bitmap, center, dst, paint);
1962}
1963
1964void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001965 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001966 return;
1967 }
reed41af9662015-01-05 07:49:08 -08001968 this->onDrawSprite(bitmap, left, top, paint);
1969}
1970
reed71c3c762015-06-24 10:29:17 -07001971void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1972 const SkColor colors[], int count, SkXfermode::Mode mode,
1973 const SkRect* cull, const SkPaint* paint) {
1974 if (count <= 0) {
1975 return;
1976 }
1977 SkASSERT(atlas);
1978 SkASSERT(xform);
1979 SkASSERT(tex);
1980 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1981}
1982
reede47829b2015-08-06 10:02:53 -07001983void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1984 const SkPaint* paint, SrcRectConstraint constraint) {
1985 if (src) {
1986 this->drawImageRect(image, *src, dst, paint, constraint);
1987 } else {
1988 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1989 dst, paint, constraint);
1990 }
1991}
1992void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1993 const SkPaint* paint, SrcRectConstraint constraint) {
1994 if (src) {
1995 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1996 } else {
1997 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1998 dst, paint, constraint);
1999 }
2000}
2001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002002//////////////////////////////////////////////////////////////////////////////
2003// These are the virtual drawing methods
2004//////////////////////////////////////////////////////////////////////////////
2005
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002006void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002007 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002008 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2009 }
2010}
2011
reed41af9662015-01-05 07:49:08 -08002012void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002013 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002014 this->internalDrawPaint(paint);
2015}
2016
2017void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002018 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002019
2020 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002021 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002022 }
2023
reed@google.com4e2b3d32011-04-07 14:18:59 +00002024 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002025}
2026
reed41af9662015-01-05 07:49:08 -08002027void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2028 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002029 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002030 if ((long)count <= 0) {
2031 return;
2032 }
2033
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002034 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002035 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002036 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002037 // special-case 2 points (common for drawing a single line)
2038 if (2 == count) {
2039 r.set(pts[0], pts[1]);
2040 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002041 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002042 }
senorblanco87e066e2015-10-28 11:23:36 -07002043 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2044 return;
2045 }
2046 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002047 }
reed@google.coma584aed2012-05-16 14:06:02 +00002048
halcanary96fcdcc2015-08-27 07:41:13 -07002049 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002050
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002051 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002052
reed@android.com8a1c16f2008-12-17 15:59:43 +00002053 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002054 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002055 }
reed@google.com4b226022011-01-11 18:32:13 +00002056
reed@google.com4e2b3d32011-04-07 14:18:59 +00002057 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002058}
2059
reed41af9662015-01-05 07:49:08 -08002060void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002061 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002062 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002063 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002064 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002065 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2066 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2067 SkRect tmp(r);
2068 tmp.sort();
2069
senorblanco87e066e2015-10-28 11:23:36 -07002070 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2071 return;
2072 }
2073 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002074 }
reed@google.com4b226022011-01-11 18:32:13 +00002075
reedc83a2972015-07-16 07:40:45 -07002076 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002077
2078 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002079 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002080 }
2081
reed@google.com4e2b3d32011-04-07 14:18:59 +00002082 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002083}
2084
reed41af9662015-01-05 07:49:08 -08002085void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002086 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002087 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002088 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002089 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002090 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2091 return;
2092 }
2093 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002094 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002095
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002096 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002097
2098 while (iter.next()) {
2099 iter.fDevice->drawOval(iter, oval, looper.paint());
2100 }
2101
2102 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002103}
2104
reed41af9662015-01-05 07:49:08 -08002105void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002106 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002107 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002108 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002109 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002110 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2111 return;
2112 }
2113 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002114 }
2115
2116 if (rrect.isRect()) {
2117 // call the non-virtual version
2118 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002119 return;
2120 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002121 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002122 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2123 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002124 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002125
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002126 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002127
2128 while (iter.next()) {
2129 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2130 }
2131
2132 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002133}
2134
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002135void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2136 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002137 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002138 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002139 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002140 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2141 return;
2142 }
2143 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002144 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002145
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002146 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002147
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002148 while (iter.next()) {
2149 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2150 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002151
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002152 LOOPER_END
2153}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002154
reed41af9662015-01-05 07:49:08 -08002155void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002156 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002157 if (!path.isFinite()) {
2158 return;
2159 }
2160
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002161 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002162 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002163 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002164 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002165 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2166 return;
2167 }
2168 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002169 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002170
2171 const SkRect& r = path.getBounds();
2172 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002173 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002174 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002175 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002176 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002177 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002178
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002179 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002180
2181 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002182 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002183 }
2184
reed@google.com4e2b3d32011-04-07 14:18:59 +00002185 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002186}
2187
reeda85d4d02015-05-06 12:56:48 -07002188void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002189 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002190 SkRect bounds = SkRect::MakeXYWH(x, y,
2191 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002192 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002193 SkRect tmp = bounds;
2194 if (paint) {
2195 paint->computeFastBounds(tmp, &tmp);
2196 }
2197 if (this->quickReject(tmp)) {
2198 return;
2199 }
reeda85d4d02015-05-06 12:56:48 -07002200 }
2201
2202 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002203 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002204 paint = lazy.init();
2205 }
2206
2207 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds)
2208
2209 while (iter.next()) {
2210 iter.fDevice->drawImage(iter, image, x, y, looper.paint());
2211 }
2212
2213 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002214}
2215
reed41af9662015-01-05 07:49:08 -08002216void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002217 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002218 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
reeda85d4d02015-05-06 12:56:48 -07002219 SkRect storage;
2220 const SkRect* bounds = &dst;
halcanary96fcdcc2015-08-27 07:41:13 -07002221 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002222 storage = dst;
2223 if (paint) {
2224 paint->computeFastBounds(dst, &storage);
2225 }
2226 if (this->quickReject(storage)) {
2227 return;
2228 }
reeda85d4d02015-05-06 12:56:48 -07002229 }
2230 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002231 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002232 paint = lazy.init();
2233 }
2234
reedc83a2972015-07-16 07:40:45 -07002235 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, bounds,
2236 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002237
2238 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002239 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002240 }
2241
2242 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002243}
2244
reed41af9662015-01-05 07:49:08 -08002245void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002246 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002247 SkDEBUGCODE(bitmap.validate();)
2248
reed33366972015-10-08 09:22:02 -07002249 if (bitmap.drawsNothing()) {
2250 return;
2251 }
2252
2253 SkLazyPaint lazy;
2254 if (nullptr == paint) {
2255 paint = lazy.init();
2256 }
2257
2258 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2259
2260 SkRect storage;
2261 const SkRect* bounds = nullptr;
2262 if (paint->canComputeFastBounds()) {
2263 bitmap.getBounds(&storage);
2264 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002265 SkRect tmp = storage;
2266 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2267 return;
2268 }
2269 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002270 }
reed@google.com4b226022011-01-11 18:32:13 +00002271
reed33366972015-10-08 09:22:02 -07002272 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2273
2274 while (iter.next()) {
2275 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2276 }
2277
2278 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002279}
2280
reed@google.com9987ec32011-09-07 11:57:52 +00002281// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002282void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002283 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002284 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002285 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002286 return;
2287 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002288
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002289 SkRect storage;
2290 const SkRect* bounds = &dst;
halcanary96fcdcc2015-08-27 07:41:13 -07002291 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002292 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2293 return;
2294 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002295 }
reed@google.com3d608122011-11-21 15:16:16 +00002296
reed@google.com33535f32012-09-25 15:37:50 +00002297 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002298 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002299 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002300 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002301
reedc83a2972015-07-16 07:40:45 -07002302 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, bounds,
2303 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002304
reed@google.com33535f32012-09-25 15:37:50 +00002305 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002306 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002307 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002308
reed@google.com33535f32012-09-25 15:37:50 +00002309 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002310}
2311
reed41af9662015-01-05 07:49:08 -08002312void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002313 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002314 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002315 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002316 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002317}
2318
reed4c21dc52015-06-25 12:32:03 -07002319void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2320 const SkPaint* paint) {
2321 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2322
2323 SkRect storage;
2324 const SkRect* bounds = &dst;
halcanary96fcdcc2015-08-27 07:41:13 -07002325 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002326 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2327 return;
2328 }
reed@google.com3d608122011-11-21 15:16:16 +00002329 }
reed4c21dc52015-06-25 12:32:03 -07002330
2331 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002332 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002333 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002334 }
reed4c21dc52015-06-25 12:32:03 -07002335
2336 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2337
2338 while (iter.next()) {
2339 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002340 }
reed4c21dc52015-06-25 12:32:03 -07002341
2342 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002343}
2344
reed41af9662015-01-05 07:49:08 -08002345void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2346 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002347 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002348 SkDEBUGCODE(bitmap.validate();)
2349
reed4c21dc52015-06-25 12:32:03 -07002350 SkRect storage;
2351 const SkRect* bounds = &dst;
halcanary96fcdcc2015-08-27 07:41:13 -07002352 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002353 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2354 return;
2355 }
reed4c21dc52015-06-25 12:32:03 -07002356 }
2357
2358 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002359 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002360 paint = lazy.init();
2361 }
2362
2363 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2364
2365 while (iter.next()) {
2366 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2367 }
2368
2369 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002370}
2371
reed@google.comf67e4cf2011-03-15 20:56:58 +00002372class SkDeviceFilteredPaint {
2373public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002374 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002375 uint32_t filteredFlags = device->filterTextFlags(paint);
2376 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002377 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002378 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002379 fPaint = newPaint;
2380 } else {
2381 fPaint = &paint;
2382 }
2383 }
2384
reed@google.comf67e4cf2011-03-15 20:56:58 +00002385 const SkPaint& paint() const { return *fPaint; }
2386
2387private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002388 const SkPaint* fPaint;
2389 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002390};
2391
bungeman@google.com52c748b2011-08-22 21:30:43 +00002392void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2393 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002394 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002395 draw.fDevice->drawRect(draw, r, paint);
2396 } else {
2397 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002398 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002399 draw.fDevice->drawRect(draw, r, p);
2400 }
2401}
2402
2403void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2404 const char text[], size_t byteLength,
2405 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002406 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002407
2408 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002409 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002410 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002411 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002412 return;
2413 }
2414
2415 SkScalar width = 0;
2416 SkPoint start;
2417
2418 start.set(0, 0); // to avoid warning
2419 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2420 SkPaint::kStrikeThruText_Flag)) {
2421 width = paint.measureText(text, byteLength);
2422
2423 SkScalar offsetX = 0;
2424 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2425 offsetX = SkScalarHalf(width);
2426 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2427 offsetX = width;
2428 }
2429 start.set(x - offsetX, y);
2430 }
2431
2432 if (0 == width) {
2433 return;
2434 }
2435
2436 uint32_t flags = paint.getFlags();
2437
2438 if (flags & (SkPaint::kUnderlineText_Flag |
2439 SkPaint::kStrikeThruText_Flag)) {
2440 SkScalar textSize = paint.getTextSize();
2441 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2442 SkRect r;
2443
2444 r.fLeft = start.fX;
2445 r.fRight = start.fX + width;
2446
2447 if (flags & SkPaint::kUnderlineText_Flag) {
2448 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2449 start.fY);
2450 r.fTop = offset;
2451 r.fBottom = offset + height;
2452 DrawRect(draw, paint, r, textSize);
2453 }
2454 if (flags & SkPaint::kStrikeThruText_Flag) {
2455 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2456 start.fY);
2457 r.fTop = offset;
2458 r.fBottom = offset + height;
2459 DrawRect(draw, paint, r, textSize);
2460 }
2461 }
2462}
2463
reed@google.come0d9ce82014-04-23 04:00:17 +00002464void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2465 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002466 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002467
2468 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002469 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002470 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002471 DrawTextDecorations(iter, dfp.paint(),
2472 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473 }
2474
reed@google.com4e2b3d32011-04-07 14:18:59 +00002475 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002476}
2477
reed@google.come0d9ce82014-04-23 04:00:17 +00002478void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2479 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002480 SkPoint textOffset = SkPoint::Make(0, 0);
2481
halcanary96fcdcc2015-08-27 07:41:13 -07002482 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002483
reed@android.com8a1c16f2008-12-17 15:59:43 +00002484 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002485 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002486 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002487 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002489
reed@google.com4e2b3d32011-04-07 14:18:59 +00002490 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002491}
2492
reed@google.come0d9ce82014-04-23 04:00:17 +00002493void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2494 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002495
2496 SkPoint textOffset = SkPoint::Make(0, constY);
2497
halcanary96fcdcc2015-08-27 07:41:13 -07002498 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002499
reed@android.com8a1c16f2008-12-17 15:59:43 +00002500 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002501 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002502 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002503 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002504 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002505
reed@google.com4e2b3d32011-04-07 14:18:59 +00002506 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002507}
2508
reed@google.come0d9ce82014-04-23 04:00:17 +00002509void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2510 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002511 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002512
reed@android.com8a1c16f2008-12-17 15:59:43 +00002513 while (iter.next()) {
2514 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002515 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002516 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002517
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002518 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002519}
2520
fmalita00d5c2c2014-08-21 08:53:26 -07002521void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2522 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002523
fmalita85d5eb92015-03-04 11:20:12 -08002524 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002525 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002526 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002527 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002528 SkRect tmp;
2529 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2530 return;
2531 }
2532 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002533 }
2534
fmalita024f9962015-03-03 19:08:17 -08002535 // We cannot filter in the looper as we normally do, because the paint is
2536 // incomplete at this point (text-related attributes are embedded within blob run paints).
2537 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002538 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002539
fmalita85d5eb92015-03-04 11:20:12 -08002540 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002541
fmalitaaa1b9122014-08-28 14:32:24 -07002542 while (iter.next()) {
2543 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002544 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002545 }
2546
fmalitaaa1b9122014-08-28 14:32:24 -07002547 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002548
2549 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002550}
2551
reed@google.come0d9ce82014-04-23 04:00:17 +00002552// These will become non-virtual, so they always call the (virtual) onDraw... method
2553void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2554 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002555 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002556 this->onDrawText(text, byteLength, x, y, paint);
2557}
2558void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2559 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002560 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002561 this->onDrawPosText(text, byteLength, pos, paint);
2562}
2563void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2564 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002565 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002566 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2567}
2568void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2569 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002570 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002571 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2572}
fmalita00d5c2c2014-08-21 08:53:26 -07002573void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2574 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002575 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002576 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002577 this->onDrawTextBlob(blob, x, y, paint);
2578 }
2579}
reed@google.come0d9ce82014-04-23 04:00:17 +00002580
reed41af9662015-01-05 07:49:08 -08002581void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2582 const SkPoint verts[], const SkPoint texs[],
2583 const SkColor colors[], SkXfermode* xmode,
2584 const uint16_t indices[], int indexCount,
2585 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002586 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002587 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002588
reed@android.com8a1c16f2008-12-17 15:59:43 +00002589 while (iter.next()) {
2590 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002591 colors, xmode, indices, indexCount,
2592 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002593 }
reed@google.com4b226022011-01-11 18:32:13 +00002594
reed@google.com4e2b3d32011-04-07 14:18:59 +00002595 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002596}
2597
dandovb3c9d1c2014-08-12 08:34:29 -07002598void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2599 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002600 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002601 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002602 return;
2603 }
mtklein6cfa73a2014-08-13 13:33:49 -07002604
dandovecfff212014-08-04 10:02:00 -07002605 // Since a patch is always within the convex hull of the control points, we discard it when its
2606 // bounding rectangle is completely outside the current clip.
2607 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002608 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002609 if (this->quickReject(bounds)) {
2610 return;
2611 }
mtklein6cfa73a2014-08-13 13:33:49 -07002612
dandovb3c9d1c2014-08-12 08:34:29 -07002613 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2614}
2615
2616void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2617 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2618
halcanary96fcdcc2015-08-27 07:41:13 -07002619 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002620
dandovecfff212014-08-04 10:02:00 -07002621 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002622 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002623 }
mtklein6cfa73a2014-08-13 13:33:49 -07002624
dandovecfff212014-08-04 10:02:00 -07002625 LOOPER_END
2626}
2627
reeda8db7282015-07-07 10:22:31 -07002628void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2629 if (dr) {
2630 if (x || y) {
2631 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2632 this->onDrawDrawable(dr, &matrix);
2633 } else {
halcanary96fcdcc2015-08-27 07:41:13 -07002634 this->onDrawDrawable(dr, nullptr);
reeda8db7282015-07-07 10:22:31 -07002635 }
reed6a070dc2014-11-11 19:36:09 -08002636 }
2637}
2638
reeda8db7282015-07-07 10:22:31 -07002639void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2640 if (dr) {
2641 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002642 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002643 }
2644 this->onDrawDrawable(dr, matrix);
2645 }
2646}
2647
2648void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2649 SkRect bounds = dr->getBounds();
2650 if (matrix) {
2651 matrix->mapRect(&bounds);
2652 }
2653 if (this->quickReject(bounds)) {
2654 return;
2655 }
2656 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002657}
2658
reed71c3c762015-06-24 10:29:17 -07002659void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2660 const SkColor colors[], int count, SkXfermode::Mode mode,
2661 const SkRect* cull, const SkPaint* paint) {
2662 if (cull && this->quickReject(*cull)) {
2663 return;
2664 }
2665
2666 SkPaint pnt;
2667 if (paint) {
2668 pnt = *paint;
2669 }
2670
halcanary96fcdcc2015-08-27 07:41:13 -07002671 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002672 while (iter.next()) {
2673 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2674 }
2675 LOOPER_END
2676}
2677
reed@android.com8a1c16f2008-12-17 15:59:43 +00002678//////////////////////////////////////////////////////////////////////////////
2679// These methods are NOT virtual, and therefore must call back into virtual
2680// methods, rather than actually drawing themselves.
2681//////////////////////////////////////////////////////////////////////////////
2682
2683void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002684 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002685 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002686 SkPaint paint;
2687
2688 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002689 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002690 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002691 }
2692 this->drawPaint(paint);
2693}
2694
reed@android.com845fdac2009-06-23 03:01:32 +00002695void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002696 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002697 SkPaint paint;
2698
2699 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002700 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002701 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002702 }
2703 this->drawPaint(paint);
2704}
2705
2706void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002707 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002708 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002709
reed@android.com8a1c16f2008-12-17 15:59:43 +00002710 pt.set(x, y);
2711 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2712}
2713
2714void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002715 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002716 SkPoint pt;
2717 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002718
reed@android.com8a1c16f2008-12-17 15:59:43 +00002719 pt.set(x, y);
2720 paint.setColor(color);
2721 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2722}
2723
2724void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2725 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002726 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002727 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002728
reed@android.com8a1c16f2008-12-17 15:59:43 +00002729 pts[0].set(x0, y0);
2730 pts[1].set(x1, y1);
2731 this->drawPoints(kLines_PointMode, 2, pts, paint);
2732}
2733
2734void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2735 SkScalar right, SkScalar bottom,
2736 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002737 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002738 SkRect r;
2739
2740 r.set(left, top, right, bottom);
2741 this->drawRect(r, paint);
2742}
2743
2744void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2745 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002746 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002747 if (radius < 0) {
2748 radius = 0;
2749 }
2750
2751 SkRect r;
2752 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002753 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002754}
2755
2756void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2757 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002758 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002759 if (rx > 0 && ry > 0) {
2760 if (paint.canComputeFastBounds()) {
2761 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002762 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002763 return;
2764 }
2765 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002766 SkRRect rrect;
2767 rrect.setRectXY(r, rx, ry);
2768 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002769 } else {
2770 this->drawRect(r, paint);
2771 }
2772}
2773
reed@android.com8a1c16f2008-12-17 15:59:43 +00002774void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2775 SkScalar sweepAngle, bool useCenter,
2776 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002777 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002778 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2779 this->drawOval(oval, paint);
2780 } else {
2781 SkPath path;
2782 if (useCenter) {
2783 path.moveTo(oval.centerX(), oval.centerY());
2784 }
2785 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2786 if (useCenter) {
2787 path.close();
2788 }
2789 this->drawPath(path, paint);
2790 }
2791}
2792
2793void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2794 const SkPath& path, SkScalar hOffset,
2795 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002796 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002797 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002798
reed@android.com8a1c16f2008-12-17 15:59:43 +00002799 matrix.setTranslate(hOffset, vOffset);
2800 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2801}
2802
reed@android.comf76bacf2009-05-13 14:00:33 +00002803///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002804
2805/**
2806 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2807 * against the playback cost of recursing into the subpicture to get at its actual ops.
2808 *
2809 * For now we pick a conservatively small value, though measurement (and other heuristics like
2810 * the type of ops contained) may justify changing this value.
2811 */
2812#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002813
reedd5fa1a42014-08-09 11:08:05 -07002814void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002815 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002816 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002817 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002818 matrix = nullptr;
reedd5fa1a42014-08-09 11:08:05 -07002819 }
reed1c2c4412015-04-30 13:09:24 -07002820 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2821 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2822 picture->playback(this);
2823 } else {
2824 this->onDrawPicture(picture, matrix, paint);
2825 }
reedd5fa1a42014-08-09 11:08:05 -07002826 }
2827}
robertphillips9b14f262014-06-04 05:40:44 -07002828
reedd5fa1a42014-08-09 11:08:05 -07002829void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2830 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002831 if (!paint || paint->canComputeFastBounds()) {
2832 SkRect bounds = picture->cullRect();
2833 if (paint) {
2834 paint->computeFastBounds(bounds, &bounds);
2835 }
2836 if (matrix) {
2837 matrix->mapRect(&bounds);
2838 }
2839 if (this->quickReject(bounds)) {
2840 return;
2841 }
2842 }
2843
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002844 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002845 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002846 // Canvas has to first give the device the opportunity to render
2847 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002848 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002849 return; // the device has rendered the entire picture
2850 }
2851 }
2852
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002853 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002854 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002855}
2856
reed@android.com8a1c16f2008-12-17 15:59:43 +00002857///////////////////////////////////////////////////////////////////////////////
2858///////////////////////////////////////////////////////////////////////////////
2859
2860SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002861 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002862
2863 SkASSERT(canvas);
2864
2865 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2866 fDone = !fImpl->next();
2867}
2868
2869SkCanvas::LayerIter::~LayerIter() {
2870 fImpl->~SkDrawIter();
2871}
2872
2873void SkCanvas::LayerIter::next() {
2874 fDone = !fImpl->next();
2875}
2876
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002877SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002878 return fImpl->getDevice();
2879}
2880
2881const SkMatrix& SkCanvas::LayerIter::matrix() const {
2882 return fImpl->getMatrix();
2883}
2884
2885const SkPaint& SkCanvas::LayerIter::paint() const {
2886 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002887 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002888 paint = &fDefaultPaint;
2889 }
2890 return *paint;
2891}
2892
2893const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2894int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2895int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002896
2897///////////////////////////////////////////////////////////////////////////////
2898
fmalitac3b589a2014-06-05 12:40:07 -07002899SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002900
2901///////////////////////////////////////////////////////////////////////////////
2902
2903static bool supported_for_raster_canvas(const SkImageInfo& info) {
2904 switch (info.alphaType()) {
2905 case kPremul_SkAlphaType:
2906 case kOpaque_SkAlphaType:
2907 break;
2908 default:
2909 return false;
2910 }
2911
2912 switch (info.colorType()) {
2913 case kAlpha_8_SkColorType:
2914 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002915 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002916 break;
2917 default:
2918 return false;
2919 }
2920
2921 return true;
2922}
2923
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002924SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2925 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002926 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002927 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002928
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002929 SkBitmap bitmap;
2930 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002931 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002932 }
halcanary385fe4d2015-08-26 13:07:48 -07002933 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002934}
reedd5fa1a42014-08-09 11:08:05 -07002935
2936///////////////////////////////////////////////////////////////////////////////
2937
2938SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002939 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002940 : fCanvas(canvas)
2941 , fSaveCount(canvas->getSaveCount())
2942{
bsalomon49f085d2014-09-05 13:34:00 -07002943 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002944 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002945 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002946 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002947 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002948 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002949 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002950 canvas->save();
2951 }
mtklein6cfa73a2014-08-13 13:33:49 -07002952
bsalomon49f085d2014-09-05 13:34:00 -07002953 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002954 canvas->concat(*matrix);
2955 }
2956}
2957
2958SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2959 fCanvas->restoreToCount(fSaveCount);
2960}