blob: 1e49fe272df04a9b8af1e8afd50cb7642488c7c5 [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
robertphillips125f19a2015-11-23 09:00:05 -08001589 fMCRec->fRasterClip.op(transformedRRect, this->getBaseLayerSize(), op,
1590 kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001591 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001592 }
1593
1594 SkPath path;
1595 path.addRRect(rrect);
1596 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001597 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001598}
1599
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001600void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001601 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001602 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
robertphillips39f05382015-11-24 09:30:12 -08001603
1604 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1605 SkRect r;
1606 if (path.isRect(&r)) {
1607 this->onClipRect(r, op, edgeStyle);
1608 return;
1609 }
1610 SkRRect rrect;
1611 if (path.isOval(&r)) {
1612 rrect.setOval(r);
1613 this->onClipRRect(rrect, op, edgeStyle);
1614 return;
1615 }
1616 if (path.isRRect(&rrect)) {
1617 this->onClipRRect(rrect, op, edgeStyle);
1618 return;
1619 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001620 }
robertphillips39f05382015-11-24 09:30:12 -08001621
1622 this->onClipPath(path, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001623}
1624
1625void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001626#ifdef SK_ENABLE_CLIP_QUICKREJECT
1627 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001628 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001629 return false;
1630 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001631
reed@google.com3b3e8952012-08-16 20:53:31 +00001632 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001633 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001634 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001635
reed687fa1c2015-04-07 08:00:56 -07001636 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001637 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001638 }
1639 }
1640#endif
1641
reed@google.com5c3d1472011-02-22 19:12:23 +00001642 AutoValidateClip avc(this);
1643
reed@android.com8a1c16f2008-12-17 15:59:43 +00001644 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001645 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001646 if (!fAllowSoftClip) {
1647 edgeStyle = kHard_ClipEdgeStyle;
1648 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001649
1650 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001651 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001652
reed@google.comfe701122011-11-08 19:41:23 +00001653 // Check if the transfomation, or the original path itself
1654 // made us empty. Note this can also happen if we contained NaN
1655 // values. computing the bounds detects this, and will set our
1656 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1657 if (devPath.getBounds().isEmpty()) {
1658 // resetting the path will remove any NaN or other wanky values
1659 // that might upset our scan converter.
1660 devPath.reset();
1661 }
1662
reed@google.com5c3d1472011-02-22 19:12:23 +00001663 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001664 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001665
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001666 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001667 bool clipIsAA = getClipStack()->asPath(&devPath);
1668 if (clipIsAA) {
1669 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001670 }
fmalita1a481fe2015-02-04 07:39:34 -08001671
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001672 op = SkRegion::kReplace_Op;
1673 }
1674
reed73e714e2014-09-04 09:02:23 -07001675 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001676}
1677
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001678void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001679 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001680 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001681}
1682
1683void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001684 AutoValidateClip avc(this);
1685
reed@android.com8a1c16f2008-12-17 15:59:43 +00001686 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001687 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001688
reed@google.com5c3d1472011-02-22 19:12:23 +00001689 // todo: signal fClipStack that we have a region, and therefore (I guess)
1690 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001691 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001692
reed1f836ee2014-07-07 07:49:34 -07001693 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001694}
1695
reed@google.com819c9212011-02-23 18:56:55 +00001696#ifdef SK_DEBUG
1697void SkCanvas::validateClip() const {
1698 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001699 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001700 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001701 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001702 return;
1703 }
1704
reed@google.com819c9212011-02-23 18:56:55 +00001705 SkIRect ir;
1706 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001707 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001708
reed687fa1c2015-04-07 08:00:56 -07001709 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001710 const SkClipStack::Element* element;
halcanary96fcdcc2015-08-27 07:41:13 -07001711 while ((element = iter.next()) != nullptr) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001712 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001713 case SkClipStack::Element::kRect_Type:
1714 element->getRect().round(&ir);
1715 tmpClip.op(ir, element->getOp());
1716 break;
1717 case SkClipStack::Element::kEmpty_Type:
1718 tmpClip.setEmpty();
1719 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001720 default: {
1721 SkPath path;
1722 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001723 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001724 break;
1725 }
reed@google.com819c9212011-02-23 18:56:55 +00001726 }
1727 }
reed@google.com819c9212011-02-23 18:56:55 +00001728}
1729#endif
1730
reed@google.com90c07ea2012-04-13 13:50:27 +00001731void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001732 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001733 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001734
halcanary96fcdcc2015-08-27 07:41:13 -07001735 while ((element = iter.next()) != nullptr) {
fmalitac3b589a2014-06-05 12:40:07 -07001736 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001737 }
1738}
1739
reed@google.com5c3d1472011-02-22 19:12:23 +00001740///////////////////////////////////////////////////////////////////////////////
1741
reed@google.com754de5f2014-02-24 19:38:20 +00001742bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001743 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001744}
1745
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001746bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001747 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001748}
1749
reed@google.com3b3e8952012-08-16 20:53:31 +00001750bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001751 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001752 return true;
1753
reed1f836ee2014-07-07 07:49:34 -07001754 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001755 return true;
1756 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001757
reed1f836ee2014-07-07 07:49:34 -07001758 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001759 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001760 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001761 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001762 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001763 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001764
reed@android.coma380ae42009-07-21 01:17:02 +00001765 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001766 // TODO: should we use | instead, or compare all 4 at once?
1767 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001768 return true;
1769 }
reed@google.comc0784db2013-12-13 21:16:12 +00001770 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001771 return true;
1772 }
1773 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001774 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001775}
1776
reed@google.com3b3e8952012-08-16 20:53:31 +00001777bool SkCanvas::quickReject(const SkPath& path) const {
1778 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001779}
1780
reed@google.com3b3e8952012-08-16 20:53:31 +00001781bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001782 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001783 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001784 return false;
1785 }
1786
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001787 SkMatrix inverse;
1788 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001789 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001790 if (bounds) {
1791 bounds->setEmpty();
1792 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001793 return false;
1794 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001795
bsalomon49f085d2014-09-05 13:34:00 -07001796 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001797 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001798 // adjust it outwards in case we are antialiasing
1799 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001800
reed@google.com8f4d2302013-12-17 16:44:46 +00001801 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1802 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001803 inverse.mapRect(bounds, r);
1804 }
1805 return true;
1806}
1807
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001808bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001809 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001810 if (clip.isEmpty()) {
1811 if (bounds) {
1812 bounds->setEmpty();
1813 }
1814 return false;
1815 }
1816
bsalomon49f085d2014-09-05 13:34:00 -07001817 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001818 *bounds = clip.getBounds();
1819 }
1820 return true;
1821}
1822
reed@android.com8a1c16f2008-12-17 15:59:43 +00001823const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001824 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001825}
1826
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001827const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001828 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001829}
1830
reed@google.com9c135db2014-03-12 18:28:35 +00001831GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1832 SkBaseDevice* dev = this->getTopDevice();
halcanary96fcdcc2015-08-27 07:41:13 -07001833 return dev ? dev->accessRenderTarget() : nullptr;
reed@google.com9c135db2014-03-12 18:28:35 +00001834}
1835
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001836GrContext* SkCanvas::getGrContext() {
1837#if SK_SUPPORT_GPU
1838 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001839 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001840 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001841 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001842 return renderTarget->getContext();
1843 }
1844 }
1845#endif
1846
halcanary96fcdcc2015-08-27 07:41:13 -07001847 return nullptr;
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001848
1849}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001850
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001851void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1852 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001853 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001854 if (outer.isEmpty()) {
1855 return;
1856 }
1857 if (inner.isEmpty()) {
1858 this->drawRRect(outer, paint);
1859 return;
1860 }
1861
1862 // We don't have this method (yet), but technically this is what we should
1863 // be able to assert...
1864 // SkASSERT(outer.contains(inner));
1865 //
1866 // For now at least check for containment of bounds
1867 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1868
1869 this->onDrawDRRect(outer, inner, paint);
1870}
1871
reed41af9662015-01-05 07:49:08 -08001872// These need to stop being virtual -- clients need to override the onDraw... versions
1873
1874void SkCanvas::drawPaint(const SkPaint& paint) {
1875 this->onDrawPaint(paint);
1876}
1877
1878void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1879 this->onDrawRect(r, paint);
1880}
1881
1882void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1883 this->onDrawOval(r, paint);
1884}
1885
1886void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1887 this->onDrawRRect(rrect, paint);
1888}
1889
1890void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1891 this->onDrawPoints(mode, count, pts, paint);
1892}
1893
1894void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1895 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1896 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1897 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1898 indices, indexCount, paint);
1899}
1900
1901void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1902 this->onDrawPath(path, paint);
1903}
1904
reeda85d4d02015-05-06 12:56:48 -07001905void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1906 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001907}
1908
reede47829b2015-08-06 10:02:53 -07001909void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1910 const SkPaint* paint, SrcRectConstraint constraint) {
1911 if (dst.isEmpty() || src.isEmpty()) {
1912 return;
1913 }
1914 this->onDrawImageRect(image, &src, dst, paint, constraint);
1915}
reed41af9662015-01-05 07:49:08 -08001916
reed84984ef2015-07-17 07:09:43 -07001917void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1918 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001919 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001920}
1921
reede47829b2015-08-06 10:02:53 -07001922void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1923 SrcRectConstraint constraint) {
1924 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1925 constraint);
1926}
reede47829b2015-08-06 10:02:53 -07001927
reed4c21dc52015-06-25 12:32:03 -07001928void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1929 const SkPaint* paint) {
1930 if (dst.isEmpty()) {
1931 return;
1932 }
1933 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
reede47829b2015-08-06 10:02:53 -07001934 this->drawImageRect(image, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001935 }
1936 this->onDrawImageNine(image, center, dst, paint);
1937}
1938
reed41af9662015-01-05 07:49:08 -08001939void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001940 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001941 return;
1942 }
reed41af9662015-01-05 07:49:08 -08001943 this->onDrawBitmap(bitmap, dx, dy, paint);
1944}
1945
reede47829b2015-08-06 10:02:53 -07001946void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07001947 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001948 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
reeda5517e22015-07-14 10:54:12 -07001949 return;
1950 }
reede47829b2015-08-06 10:02:53 -07001951 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
reed41af9662015-01-05 07:49:08 -08001952}
1953
reed84984ef2015-07-17 07:09:43 -07001954void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1955 const SkPaint* paint, SrcRectConstraint constraint) {
reede47829b2015-08-06 10:02:53 -07001956 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
reed84984ef2015-07-17 07:09:43 -07001957}
1958
reede47829b2015-08-06 10:02:53 -07001959void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1960 SrcRectConstraint constraint) {
1961 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1962 constraint);
1963}
reede47829b2015-08-06 10:02:53 -07001964
reed41af9662015-01-05 07:49:08 -08001965void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1966 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001967 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001968 return;
1969 }
reed4c21dc52015-06-25 12:32:03 -07001970 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001971 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001972 }
reed41af9662015-01-05 07:49:08 -08001973 this->onDrawBitmapNine(bitmap, center, dst, paint);
1974}
1975
1976void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001977 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001978 return;
1979 }
reed41af9662015-01-05 07:49:08 -08001980 this->onDrawSprite(bitmap, left, top, paint);
1981}
1982
reed71c3c762015-06-24 10:29:17 -07001983void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1984 const SkColor colors[], int count, SkXfermode::Mode mode,
1985 const SkRect* cull, const SkPaint* paint) {
1986 if (count <= 0) {
1987 return;
1988 }
1989 SkASSERT(atlas);
1990 SkASSERT(xform);
1991 SkASSERT(tex);
1992 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1993}
1994
reede47829b2015-08-06 10:02:53 -07001995void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1996 const SkPaint* paint, SrcRectConstraint constraint) {
1997 if (src) {
1998 this->drawImageRect(image, *src, dst, paint, constraint);
1999 } else {
2000 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
2001 dst, paint, constraint);
2002 }
2003}
2004void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2005 const SkPaint* paint, SrcRectConstraint constraint) {
2006 if (src) {
2007 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
2008 } else {
2009 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
2010 dst, paint, constraint);
2011 }
2012}
2013
reed@android.com8a1c16f2008-12-17 15:59:43 +00002014//////////////////////////////////////////////////////////////////////////////
2015// These are the virtual drawing methods
2016//////////////////////////////////////////////////////////////////////////////
2017
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002018void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07002019 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00002020 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2021 }
2022}
2023
reed41af9662015-01-05 07:49:08 -08002024void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002025 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002026 this->internalDrawPaint(paint);
2027}
2028
2029void SkCanvas::internalDrawPaint(const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002030 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002031
2032 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002033 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002034 }
2035
reed@google.com4e2b3d32011-04-07 14:18:59 +00002036 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002037}
2038
reed41af9662015-01-05 07:49:08 -08002039void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2040 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002041 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00002042 if ((long)count <= 0) {
2043 return;
2044 }
2045
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002046 SkRect r, storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002047 const SkRect* bounds = nullptr;
reed@google.coma584aed2012-05-16 14:06:02 +00002048 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00002049 // special-case 2 points (common for drawing a single line)
2050 if (2 == count) {
2051 r.set(pts[0], pts[1]);
2052 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00002053 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00002054 }
senorblanco87e066e2015-10-28 11:23:36 -07002055 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2056 return;
2057 }
2058 bounds = &r;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002059 }
reed@google.coma584aed2012-05-16 14:06:02 +00002060
halcanary96fcdcc2015-08-27 07:41:13 -07002061 SkASSERT(pts != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002062
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002063 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00002064
reed@android.com8a1c16f2008-12-17 15:59:43 +00002065 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002066 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002067 }
reed@google.com4b226022011-01-11 18:32:13 +00002068
reed@google.com4e2b3d32011-04-07 14:18:59 +00002069 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002070}
2071
reed41af9662015-01-05 07:49:08 -08002072void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002073 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002074 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002075 const SkRect* bounds = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002076 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08002077 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2078 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2079 SkRect tmp(r);
2080 tmp.sort();
2081
senorblanco87e066e2015-10-28 11:23:36 -07002082 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2083 return;
2084 }
2085 bounds = &r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002086 }
reed@google.com4b226022011-01-11 18:32:13 +00002087
reedc83a2972015-07-16 07:40:45 -07002088 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002089
2090 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002091 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002092 }
2093
reed@google.com4e2b3d32011-04-07 14:18:59 +00002094 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002095}
2096
reed41af9662015-01-05 07:49:08 -08002097void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002098 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002099 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002100 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002101 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002102 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2103 return;
2104 }
2105 bounds = &oval;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002106 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00002107
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002108 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00002109
2110 while (iter.next()) {
2111 iter.fDevice->drawOval(iter, oval, looper.paint());
2112 }
2113
2114 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002115}
2116
reed41af9662015-01-05 07:49:08 -08002117void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002118 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002119 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002120 const SkRect* bounds = nullptr;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002121 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002122 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2123 return;
2124 }
2125 bounds = &rrect.getBounds();
reed@google.com4ed0fb72012-12-12 20:48:18 +00002126 }
2127
2128 if (rrect.isRect()) {
2129 // call the non-virtual version
2130 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002131 return;
2132 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00002133 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002134 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2135 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00002136 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002137
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002138 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00002139
2140 while (iter.next()) {
2141 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2142 }
2143
2144 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00002145}
2146
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002147void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2148 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002149 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002150 const SkRect* bounds = nullptr;
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002151 if (paint.canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002152 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2153 return;
2154 }
2155 bounds = &outer.getBounds();
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002156 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002157
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002158 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002159
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002160 while (iter.next()) {
2161 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2162 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00002163
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00002164 LOOPER_END
2165}
reed@google.com4ed0fb72012-12-12 20:48:18 +00002166
reed41af9662015-01-05 07:49:08 -08002167void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002168 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00002169 if (!path.isFinite()) {
2170 return;
2171 }
2172
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002173 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002174 const SkRect* bounds = nullptr;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002175 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002176 const SkRect& pathBounds = path.getBounds();
senorblanco87e066e2015-10-28 11:23:36 -07002177 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2178 return;
2179 }
2180 bounds = &pathBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002181 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002182
2183 const SkRect& r = path.getBounds();
2184 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002185 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002186 this->internalDrawPaint(paint);
caryclark6651a322015-09-09 13:20:49 -07002187 return;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002188 }
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002189 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002190
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002191 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002192
2193 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002194 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002195 }
2196
reed@google.com4e2b3d32011-04-07 14:18:59 +00002197 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002198}
2199
reeda85d4d02015-05-06 12:56:48 -07002200void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002201 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002202 SkRect bounds = SkRect::MakeXYWH(x, y,
2203 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
halcanary96fcdcc2015-08-27 07:41:13 -07002204 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002205 SkRect tmp = bounds;
2206 if (paint) {
2207 paint->computeFastBounds(tmp, &tmp);
2208 }
2209 if (this->quickReject(tmp)) {
2210 return;
2211 }
reeda85d4d02015-05-06 12:56:48 -07002212 }
2213
2214 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002215 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002216 paint = lazy.init();
2217 }
2218
2219 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds)
2220
2221 while (iter.next()) {
2222 iter.fDevice->drawImage(iter, image, x, y, looper.paint());
2223 }
2224
2225 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002226}
2227
reed41af9662015-01-05 07:49:08 -08002228void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002229 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002230 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
reeda85d4d02015-05-06 12:56:48 -07002231 SkRect storage;
2232 const SkRect* bounds = &dst;
halcanary96fcdcc2015-08-27 07:41:13 -07002233 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002234 storage = dst;
2235 if (paint) {
2236 paint->computeFastBounds(dst, &storage);
2237 }
2238 if (this->quickReject(storage)) {
2239 return;
2240 }
reeda85d4d02015-05-06 12:56:48 -07002241 }
2242 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002243 if (nullptr == paint) {
reeda85d4d02015-05-06 12:56:48 -07002244 paint = lazy.init();
2245 }
2246
reedc83a2972015-07-16 07:40:45 -07002247 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, bounds,
2248 image->isOpaque())
reeda85d4d02015-05-06 12:56:48 -07002249
2250 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002251 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002252 }
2253
2254 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002255}
2256
reed41af9662015-01-05 07:49:08 -08002257void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002258 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002259 SkDEBUGCODE(bitmap.validate();)
2260
reed33366972015-10-08 09:22:02 -07002261 if (bitmap.drawsNothing()) {
2262 return;
2263 }
2264
2265 SkLazyPaint lazy;
2266 if (nullptr == paint) {
2267 paint = lazy.init();
2268 }
2269
2270 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2271
2272 SkRect storage;
2273 const SkRect* bounds = nullptr;
2274 if (paint->canComputeFastBounds()) {
2275 bitmap.getBounds(&storage);
2276 matrix.mapRect(&storage);
senorblanco87e066e2015-10-28 11:23:36 -07002277 SkRect tmp = storage;
2278 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2279 return;
2280 }
2281 bounds = &storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00002282 }
reed@google.com4b226022011-01-11 18:32:13 +00002283
reed33366972015-10-08 09:22:02 -07002284 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2285
2286 while (iter.next()) {
2287 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2288 }
2289
2290 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002291}
2292
reed@google.com9987ec32011-09-07 11:57:52 +00002293// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002294void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002295 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002296 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002297 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002298 return;
2299 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002300
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002301 SkRect storage;
2302 const SkRect* bounds = &dst;
halcanary96fcdcc2015-08-27 07:41:13 -07002303 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002304 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2305 return;
2306 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307 }
reed@google.com3d608122011-11-21 15:16:16 +00002308
reed@google.com33535f32012-09-25 15:37:50 +00002309 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002310 if (nullptr == paint) {
reed@google.com33535f32012-09-25 15:37:50 +00002311 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002312 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002313
reedc83a2972015-07-16 07:40:45 -07002314 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, bounds,
2315 bitmap.isOpaque())
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002316
reed@google.com33535f32012-09-25 15:37:50 +00002317 while (iter.next()) {
reed562fe472015-07-28 07:35:14 -07002318 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002319 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002320
reed@google.com33535f32012-09-25 15:37:50 +00002321 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002322}
2323
reed41af9662015-01-05 07:49:08 -08002324void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -07002325 const SkPaint* paint, SrcRectConstraint constraint) {
danakj9881d632014-11-26 12:41:06 -08002326 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002327 SkDEBUGCODE(bitmap.validate();)
reed562fe472015-07-28 07:35:14 -07002328 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002329}
2330
reed4c21dc52015-06-25 12:32:03 -07002331void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2332 const SkPaint* paint) {
2333 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2334
2335 SkRect storage;
2336 const SkRect* bounds = &dst;
halcanary96fcdcc2015-08-27 07:41:13 -07002337 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002338 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2339 return;
2340 }
reed@google.com3d608122011-11-21 15:16:16 +00002341 }
reed4c21dc52015-06-25 12:32:03 -07002342
2343 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002344 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002345 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002346 }
reed4c21dc52015-06-25 12:32:03 -07002347
2348 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2349
2350 while (iter.next()) {
2351 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002352 }
reed4c21dc52015-06-25 12:32:03 -07002353
2354 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002355}
2356
reed41af9662015-01-05 07:49:08 -08002357void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2358 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002359 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002360 SkDEBUGCODE(bitmap.validate();)
2361
reed4c21dc52015-06-25 12:32:03 -07002362 SkRect storage;
2363 const SkRect* bounds = &dst;
halcanary96fcdcc2015-08-27 07:41:13 -07002364 if (nullptr == paint || paint->canComputeFastBounds()) {
senorblanco87e066e2015-10-28 11:23:36 -07002365 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2366 return;
2367 }
reed4c21dc52015-06-25 12:32:03 -07002368 }
2369
2370 SkLazyPaint lazy;
halcanary96fcdcc2015-08-27 07:41:13 -07002371 if (nullptr == paint) {
reed4c21dc52015-06-25 12:32:03 -07002372 paint = lazy.init();
2373 }
2374
2375 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2376
2377 while (iter.next()) {
2378 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2379 }
2380
2381 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002382}
2383
reed@google.comf67e4cf2011-03-15 20:56:58 +00002384class SkDeviceFilteredPaint {
2385public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002386 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002387 uint32_t filteredFlags = device->filterTextFlags(paint);
2388 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002389 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002390 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002391 fPaint = newPaint;
2392 } else {
2393 fPaint = &paint;
2394 }
2395 }
2396
reed@google.comf67e4cf2011-03-15 20:56:58 +00002397 const SkPaint& paint() const { return *fPaint; }
2398
2399private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002400 const SkPaint* fPaint;
2401 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002402};
2403
bungeman@google.com52c748b2011-08-22 21:30:43 +00002404void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2405 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002406 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002407 draw.fDevice->drawRect(draw, r, paint);
2408 } else {
2409 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002410 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002411 draw.fDevice->drawRect(draw, r, p);
2412 }
2413}
2414
2415void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2416 const char text[], size_t byteLength,
2417 SkScalar x, SkScalar y) {
halcanary96fcdcc2015-08-27 07:41:13 -07002418 SkASSERT(byteLength == 0 || text != nullptr);
bungeman@google.com52c748b2011-08-22 21:30:43 +00002419
2420 // nothing to draw
halcanary96fcdcc2015-08-27 07:41:13 -07002421 if (text == nullptr || byteLength == 0 ||
bungeman@google.com52c748b2011-08-22 21:30:43 +00002422 draw.fClip->isEmpty() ||
halcanary96fcdcc2015-08-27 07:41:13 -07002423 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002424 return;
2425 }
2426
2427 SkScalar width = 0;
2428 SkPoint start;
2429
2430 start.set(0, 0); // to avoid warning
2431 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2432 SkPaint::kStrikeThruText_Flag)) {
2433 width = paint.measureText(text, byteLength);
2434
2435 SkScalar offsetX = 0;
2436 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2437 offsetX = SkScalarHalf(width);
2438 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2439 offsetX = width;
2440 }
2441 start.set(x - offsetX, y);
2442 }
2443
2444 if (0 == width) {
2445 return;
2446 }
2447
2448 uint32_t flags = paint.getFlags();
2449
2450 if (flags & (SkPaint::kUnderlineText_Flag |
2451 SkPaint::kStrikeThruText_Flag)) {
2452 SkScalar textSize = paint.getTextSize();
2453 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2454 SkRect r;
2455
2456 r.fLeft = start.fX;
2457 r.fRight = start.fX + width;
2458
2459 if (flags & SkPaint::kUnderlineText_Flag) {
2460 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2461 start.fY);
2462 r.fTop = offset;
2463 r.fBottom = offset + height;
2464 DrawRect(draw, paint, r, textSize);
2465 }
2466 if (flags & SkPaint::kStrikeThruText_Flag) {
2467 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2468 start.fY);
2469 r.fTop = offset;
2470 r.fBottom = offset + height;
2471 DrawRect(draw, paint, r, textSize);
2472 }
2473 }
2474}
2475
reed@google.come0d9ce82014-04-23 04:00:17 +00002476void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2477 const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002478 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002479
2480 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002481 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002482 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002483 DrawTextDecorations(iter, dfp.paint(),
2484 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002485 }
2486
reed@google.com4e2b3d32011-04-07 14:18:59 +00002487 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002488}
2489
reed@google.come0d9ce82014-04-23 04:00:17 +00002490void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2491 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002492 SkPoint textOffset = SkPoint::Make(0, 0);
2493
halcanary96fcdcc2015-08-27 07:41:13 -07002494 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002495
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002497 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002498 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002499 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002500 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002501
reed@google.com4e2b3d32011-04-07 14:18:59 +00002502 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002503}
2504
reed@google.come0d9ce82014-04-23 04:00:17 +00002505void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2506 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002507
2508 SkPoint textOffset = SkPoint::Make(0, constY);
2509
halcanary96fcdcc2015-08-27 07:41:13 -07002510 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002511
reed@android.com8a1c16f2008-12-17 15:59:43 +00002512 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002513 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002514 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002515 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002516 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002517
reed@google.com4e2b3d32011-04-07 14:18:59 +00002518 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002519}
2520
reed@google.come0d9ce82014-04-23 04:00:17 +00002521void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2522 const SkMatrix* matrix, const SkPaint& paint) {
halcanary96fcdcc2015-08-27 07:41:13 -07002523 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002524
reed@android.com8a1c16f2008-12-17 15:59:43 +00002525 while (iter.next()) {
2526 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002527 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002528 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002529
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002530 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002531}
2532
fmalita00d5c2c2014-08-21 08:53:26 -07002533void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2534 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002535
fmalita85d5eb92015-03-04 11:20:12 -08002536 SkRect storage;
halcanary96fcdcc2015-08-27 07:41:13 -07002537 const SkRect* bounds = nullptr;
fmalita19653d12014-10-16 11:53:30 -07002538 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002539 storage = blob->bounds().makeOffset(x, y);
senorblanco87e066e2015-10-28 11:23:36 -07002540 SkRect tmp;
2541 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2542 return;
2543 }
2544 bounds = &storage;
fmalita7ba7aa72014-08-29 09:46:36 -07002545 }
2546
fmalita024f9962015-03-03 19:08:17 -08002547 // We cannot filter in the looper as we normally do, because the paint is
2548 // incomplete at this point (text-related attributes are embedded within blob run paints).
2549 SkDrawFilter* drawFilter = fMCRec->fFilter;
halcanary96fcdcc2015-08-27 07:41:13 -07002550 fMCRec->fFilter = nullptr;
fmalita024f9962015-03-03 19:08:17 -08002551
fmalita85d5eb92015-03-04 11:20:12 -08002552 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002553
fmalitaaa1b9122014-08-28 14:32:24 -07002554 while (iter.next()) {
2555 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002556 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002557 }
2558
fmalitaaa1b9122014-08-28 14:32:24 -07002559 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002560
2561 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002562}
2563
reed@google.come0d9ce82014-04-23 04:00:17 +00002564// These will become non-virtual, so they always call the (virtual) onDraw... method
2565void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2566 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002567 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002568 this->onDrawText(text, byteLength, x, y, paint);
2569}
2570void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2571 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002572 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002573 this->onDrawPosText(text, byteLength, pos, paint);
2574}
2575void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2576 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002577 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002578 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2579}
2580void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2581 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002582 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002583 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2584}
fmalita00d5c2c2014-08-21 08:53:26 -07002585void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2586 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002587 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002588 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002589 this->onDrawTextBlob(blob, x, y, paint);
2590 }
2591}
reed@google.come0d9ce82014-04-23 04:00:17 +00002592
reed41af9662015-01-05 07:49:08 -08002593void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2594 const SkPoint verts[], const SkPoint texs[],
2595 const SkColor colors[], SkXfermode* xmode,
2596 const uint16_t indices[], int indexCount,
2597 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002598 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
halcanary96fcdcc2015-08-27 07:41:13 -07002599 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
reed@google.com4b226022011-01-11 18:32:13 +00002600
reed@android.com8a1c16f2008-12-17 15:59:43 +00002601 while (iter.next()) {
2602 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002603 colors, xmode, indices, indexCount,
2604 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002605 }
reed@google.com4b226022011-01-11 18:32:13 +00002606
reed@google.com4e2b3d32011-04-07 14:18:59 +00002607 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002608}
2609
dandovb3c9d1c2014-08-12 08:34:29 -07002610void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2611 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002612 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
halcanary96fcdcc2015-08-27 07:41:13 -07002613 if (nullptr == cubics) {
dandovb3c9d1c2014-08-12 08:34:29 -07002614 return;
2615 }
mtklein6cfa73a2014-08-13 13:33:49 -07002616
dandovecfff212014-08-04 10:02:00 -07002617 // Since a patch is always within the convex hull of the control points, we discard it when its
2618 // bounding rectangle is completely outside the current clip.
2619 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002620 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002621 if (this->quickReject(bounds)) {
2622 return;
2623 }
mtklein6cfa73a2014-08-13 13:33:49 -07002624
dandovb3c9d1c2014-08-12 08:34:29 -07002625 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2626}
2627
2628void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2629 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2630
halcanary96fcdcc2015-08-27 07:41:13 -07002631 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
mtklein6cfa73a2014-08-13 13:33:49 -07002632
dandovecfff212014-08-04 10:02:00 -07002633 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002634 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002635 }
mtklein6cfa73a2014-08-13 13:33:49 -07002636
dandovecfff212014-08-04 10:02:00 -07002637 LOOPER_END
2638}
2639
reeda8db7282015-07-07 10:22:31 -07002640void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2641 if (dr) {
2642 if (x || y) {
2643 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2644 this->onDrawDrawable(dr, &matrix);
2645 } else {
halcanary96fcdcc2015-08-27 07:41:13 -07002646 this->onDrawDrawable(dr, nullptr);
reeda8db7282015-07-07 10:22:31 -07002647 }
reed6a070dc2014-11-11 19:36:09 -08002648 }
2649}
2650
reeda8db7282015-07-07 10:22:31 -07002651void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2652 if (dr) {
2653 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002654 matrix = nullptr;
reeda8db7282015-07-07 10:22:31 -07002655 }
2656 this->onDrawDrawable(dr, matrix);
2657 }
2658}
2659
2660void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2661 SkRect bounds = dr->getBounds();
2662 if (matrix) {
2663 matrix->mapRect(&bounds);
2664 }
2665 if (this->quickReject(bounds)) {
2666 return;
2667 }
2668 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002669}
2670
reed71c3c762015-06-24 10:29:17 -07002671void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2672 const SkColor colors[], int count, SkXfermode::Mode mode,
2673 const SkRect* cull, const SkPaint* paint) {
2674 if (cull && this->quickReject(*cull)) {
2675 return;
2676 }
2677
2678 SkPaint pnt;
2679 if (paint) {
2680 pnt = *paint;
2681 }
2682
halcanary96fcdcc2015-08-27 07:41:13 -07002683 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
reed71c3c762015-06-24 10:29:17 -07002684 while (iter.next()) {
2685 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2686 }
2687 LOOPER_END
2688}
2689
reed@android.com8a1c16f2008-12-17 15:59:43 +00002690//////////////////////////////////////////////////////////////////////////////
2691// These methods are NOT virtual, and therefore must call back into virtual
2692// methods, rather than actually drawing themselves.
2693//////////////////////////////////////////////////////////////////////////////
2694
2695void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002696 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002697 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002698 SkPaint paint;
2699
2700 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002701 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002702 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002703 }
2704 this->drawPaint(paint);
2705}
2706
reed@android.com845fdac2009-06-23 03:01:32 +00002707void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002708 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002709 SkPaint paint;
2710
2711 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002712 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002713 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002714 }
2715 this->drawPaint(paint);
2716}
2717
2718void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002719 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002720 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002721
reed@android.com8a1c16f2008-12-17 15:59:43 +00002722 pt.set(x, y);
2723 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2724}
2725
2726void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002727 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002728 SkPoint pt;
2729 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002730
reed@android.com8a1c16f2008-12-17 15:59:43 +00002731 pt.set(x, y);
2732 paint.setColor(color);
2733 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2734}
2735
2736void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2737 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002738 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002739 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002740
reed@android.com8a1c16f2008-12-17 15:59:43 +00002741 pts[0].set(x0, y0);
2742 pts[1].set(x1, y1);
2743 this->drawPoints(kLines_PointMode, 2, pts, paint);
2744}
2745
2746void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2747 SkScalar right, SkScalar bottom,
2748 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002749 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002750 SkRect r;
2751
2752 r.set(left, top, right, bottom);
2753 this->drawRect(r, paint);
2754}
2755
2756void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2757 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002758 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002759 if (radius < 0) {
2760 radius = 0;
2761 }
2762
2763 SkRect r;
2764 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002765 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002766}
2767
2768void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2769 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002770 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002771 if (rx > 0 && ry > 0) {
2772 if (paint.canComputeFastBounds()) {
2773 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002774 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002775 return;
2776 }
2777 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002778 SkRRect rrect;
2779 rrect.setRectXY(r, rx, ry);
2780 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002781 } else {
2782 this->drawRect(r, paint);
2783 }
2784}
2785
reed@android.com8a1c16f2008-12-17 15:59:43 +00002786void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2787 SkScalar sweepAngle, bool useCenter,
2788 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002789 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002790 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2791 this->drawOval(oval, paint);
2792 } else {
2793 SkPath path;
2794 if (useCenter) {
2795 path.moveTo(oval.centerX(), oval.centerY());
2796 }
2797 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2798 if (useCenter) {
2799 path.close();
2800 }
2801 this->drawPath(path, paint);
2802 }
2803}
2804
2805void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2806 const SkPath& path, SkScalar hOffset,
2807 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002808 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002809 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002810
reed@android.com8a1c16f2008-12-17 15:59:43 +00002811 matrix.setTranslate(hOffset, vOffset);
2812 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2813}
2814
reed@android.comf76bacf2009-05-13 14:00:33 +00002815///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002816
2817/**
2818 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2819 * against the playback cost of recursing into the subpicture to get at its actual ops.
2820 *
2821 * For now we pick a conservatively small value, though measurement (and other heuristics like
2822 * the type of ops contained) may justify changing this value.
2823 */
2824#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002825
reedd5fa1a42014-08-09 11:08:05 -07002826void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002827 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002828 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002829 if (matrix && matrix->isIdentity()) {
halcanary96fcdcc2015-08-27 07:41:13 -07002830 matrix = nullptr;
reedd5fa1a42014-08-09 11:08:05 -07002831 }
reed1c2c4412015-04-30 13:09:24 -07002832 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2833 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2834 picture->playback(this);
2835 } else {
2836 this->onDrawPicture(picture, matrix, paint);
2837 }
reedd5fa1a42014-08-09 11:08:05 -07002838 }
2839}
robertphillips9b14f262014-06-04 05:40:44 -07002840
reedd5fa1a42014-08-09 11:08:05 -07002841void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2842 const SkPaint* paint) {
fmalitad0281802015-08-20 12:08:18 -07002843 if (!paint || paint->canComputeFastBounds()) {
2844 SkRect bounds = picture->cullRect();
2845 if (paint) {
2846 paint->computeFastBounds(bounds, &bounds);
2847 }
2848 if (matrix) {
2849 matrix->mapRect(&bounds);
2850 }
2851 if (this->quickReject(bounds)) {
2852 return;
2853 }
2854 }
2855
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002856 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002857 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002858 // Canvas has to first give the device the opportunity to render
2859 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002860 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002861 return; // the device has rendered the entire picture
2862 }
2863 }
2864
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002865 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002866 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002867}
2868
reed@android.com8a1c16f2008-12-17 15:59:43 +00002869///////////////////////////////////////////////////////////////////////////////
2870///////////////////////////////////////////////////////////////////////////////
2871
2872SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
bungeman99fe8222015-08-20 07:57:51 -07002873 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002874
2875 SkASSERT(canvas);
2876
2877 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2878 fDone = !fImpl->next();
2879}
2880
2881SkCanvas::LayerIter::~LayerIter() {
2882 fImpl->~SkDrawIter();
2883}
2884
2885void SkCanvas::LayerIter::next() {
2886 fDone = !fImpl->next();
2887}
2888
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002889SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002890 return fImpl->getDevice();
2891}
2892
2893const SkMatrix& SkCanvas::LayerIter::matrix() const {
2894 return fImpl->getMatrix();
2895}
2896
2897const SkPaint& SkCanvas::LayerIter::paint() const {
2898 const SkPaint* paint = fImpl->getPaint();
halcanary96fcdcc2015-08-27 07:41:13 -07002899 if (nullptr == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002900 paint = &fDefaultPaint;
2901 }
2902 return *paint;
2903}
2904
2905const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2906int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2907int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002908
2909///////////////////////////////////////////////////////////////////////////////
2910
fmalitac3b589a2014-06-05 12:40:07 -07002911SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002912
2913///////////////////////////////////////////////////////////////////////////////
2914
2915static bool supported_for_raster_canvas(const SkImageInfo& info) {
2916 switch (info.alphaType()) {
2917 case kPremul_SkAlphaType:
2918 case kOpaque_SkAlphaType:
2919 break;
2920 default:
2921 return false;
2922 }
2923
2924 switch (info.colorType()) {
2925 case kAlpha_8_SkColorType:
2926 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002927 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002928 break;
2929 default:
2930 return false;
2931 }
2932
2933 return true;
2934}
2935
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002936SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2937 if (!supported_for_raster_canvas(info)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002938 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002939 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002940
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002941 SkBitmap bitmap;
2942 if (!bitmap.installPixels(info, pixels, rowBytes)) {
halcanary96fcdcc2015-08-27 07:41:13 -07002943 return nullptr;
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002944 }
halcanary385fe4d2015-08-26 13:07:48 -07002945 return new SkCanvas(bitmap);
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002946}
reedd5fa1a42014-08-09 11:08:05 -07002947
2948///////////////////////////////////////////////////////////////////////////////
2949
2950SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002951 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002952 : fCanvas(canvas)
2953 , fSaveCount(canvas->getSaveCount())
2954{
bsalomon49f085d2014-09-05 13:34:00 -07002955 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002956 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002957 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002958 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002959 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002960 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002961 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002962 canvas->save();
2963 }
mtklein6cfa73a2014-08-13 13:33:49 -07002964
bsalomon49f085d2014-09-05 13:34:00 -07002965 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002966 canvas->concat(*matrix);
2967 }
2968}
2969
2970SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2971 fCanvas->restoreToCount(fSaveCount);
2972}