blob: 83eee62ea0c26ef91e29fbf915eee065f6a8a5ca [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
8#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -07009#include "SkCanvasPriv.h"
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000010#include "SkBitmapDevice.h"
senorblanco@chromium.org9c397442012-09-27 21:57:45 +000011#include "SkDeviceImageFilterProxy.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080013#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDrawFilter.h"
15#include "SkDrawLooper.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080016#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070017#include "SkImage.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000018#include "SkMetaData.h"
caryclark@google.com45a75fb2013-04-25 13:34:40 +000019#include "SkPathOps.h"
dandovb3c9d1c2014-08-12 08:34:29 -070020#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000021#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000022#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080023#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000024#include "SkRRect.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000025#include "SkSmallAllocator.h"
reed@google.com97af1a62012-08-28 12:19:02 +000026#include "SkSurface_Base.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000027#include "SkTemplates.h"
fmalita7ba7aa72014-08-29 09:46:36 -070028#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000029#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000030#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080031#include "SkTraceEvent.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000032#include "SkUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000033
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000034#if SK_SUPPORT_GPU
35#include "GrRenderTarget.h"
36#endif
37
reedd990e2f2014-12-22 11:58:30 -080038static bool gIgnoreSaveLayerBounds;
39void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
40 gIgnoreSaveLayerBounds = ignore;
41}
42bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
43 return gIgnoreSaveLayerBounds;
44}
45
reed0acf1b42014-12-22 16:12:38 -080046static bool gTreatSpriteAsBitmap;
47void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
48 gTreatSpriteAsBitmap = spriteAsBitmap;
49}
50bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
51 return gTreatSpriteAsBitmap;
52}
53
reed@google.comda17f752012-08-16 18:27:05 +000054// experimental for faster tiled drawing...
55//#define SK_ENABLE_CLIP_QUICKREJECT
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000056
reed@android.com8a1c16f2008-12-17 15:59:43 +000057//#define SK_TRACE_SAVERESTORE
58
59#ifdef SK_TRACE_SAVERESTORE
60 static int gLayerCounter;
61 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
62 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
63
64 static int gRecCounter;
65 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
66 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
67
68 static int gCanvasCounter;
69 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
70 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
71#else
72 #define inc_layer()
73 #define dec_layer()
74 #define inc_rec()
75 #define dec_rec()
76 #define inc_canvas()
77 #define dec_canvas()
78#endif
79
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +000080typedef SkTLazy<SkPaint> SkLazyPaint;
81
reed@google.com97af1a62012-08-28 12:19:02 +000082void SkCanvas::predrawNotify() {
83 if (fSurfaceBase) {
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +000084 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
reed@google.com97af1a62012-08-28 12:19:02 +000085 }
86}
87
reed@android.com8a1c16f2008-12-17 15:59:43 +000088///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000089
reed4a8126e2014-09-22 07:29:03 -070090static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
91 const uint32_t propFlags = props.flags();
92 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
93 flags &= ~SkPaint::kDither_Flag;
94 }
95 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
96 flags &= ~SkPaint::kAntiAlias_Flag;
97 }
98 return flags;
99}
100
101///////////////////////////////////////////////////////////////////////////////
102
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000103/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 The clip/matrix/proc are fields that reflect the top of the save/restore
105 stack. Whenever the canvas changes, it marks a dirty flag, and then before
106 these are used (assuming we're not on a layer) we rebuild these cache
107 values: they reflect the top of the save stack, but translated and clipped
108 by the device's XY offset and bitmap-bounds.
109*/
110struct DeviceCM {
111 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000112 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000113 SkRasterClip fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 const SkMatrix* fMatrix;
reed@google.com6f8f2922011-03-04 22:27:10 +0000115 SkPaint* fPaint; // may be null (in the future)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116
reed96e657d2015-03-10 17:30:07 -0700117 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reedd9544982014-09-09 18:46:22 -0700118 bool conservativeRasterClip)
119 : fNext(NULL)
120 , fClip(conservativeRasterClip)
121 {
122 if (NULL != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000124 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125 }
reed@google.com4b226022011-01-11 18:32:13 +0000126 fDevice = device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000128 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000130 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700131 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000132 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 fDevice->unref();
134 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000135 SkDELETE(fPaint);
136 }
reed@google.com4b226022011-01-11 18:32:13 +0000137
reed@google.com045e62d2011-10-24 12:19:46 +0000138 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
139 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000140 int x = fDevice->getOrigin().x();
141 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 int width = fDevice->width();
143 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000144
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 if ((x | y) == 0) {
146 fMatrix = &totalMatrix;
147 fClip = totalClip;
148 } else {
149 fMatrixStorage = totalMatrix;
150 fMatrixStorage.postTranslate(SkIntToScalar(-x),
151 SkIntToScalar(-y));
152 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000153
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 totalClip.translate(-x, -y, &fClip);
155 }
156
reed@google.com045e62d2011-10-24 12:19:46 +0000157 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158
159 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000160
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000162 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163 SkRegion::kDifference_Op);
164 }
reed@google.com4b226022011-01-11 18:32:13 +0000165
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000166 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
167
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168#ifdef SK_DEBUG
169 if (!fClip.isEmpty()) {
170 SkIRect deviceR;
171 deviceR.set(0, 0, width, height);
172 SkASSERT(deviceR.contains(fClip.getBounds()));
173 }
174#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000175 }
176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177private:
bsalomon@google.com0e354aa2012-10-08 20:44:25 +0000178 SkMatrix fMatrixStorage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179};
180
181/* This is the record we keep for each save/restore level in the stack.
182 Since a level optionally copies the matrix and/or stack, we have pointers
183 for these fields. If the value is copied for this level, the copy is
184 stored in the ...Storage field, and the pointer points to that. If the
185 value is not copied for this level, we ignore ...Storage, and just point
186 at the corresponding value in the previous level in the stack.
187*/
188class SkCanvas::MCRec {
189public:
reed1f836ee2014-07-07 07:49:34 -0700190 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700191 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 /* If there are any layers in the stack, this points to the top-most
193 one that is at or below this level in the stack (so we know what
194 bitmap/device to draw into from this level. This value is NOT
195 reference counted, since the real owner is either our fLayer field,
196 or a previous one in a lower level.)
197 */
reed2ff1fce2014-12-11 07:07:37 -0800198 DeviceCM* fTopLayer;
199 SkRasterClip fRasterClip;
200 SkMatrix fMatrix;
201 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202
reedd9544982014-09-09 18:46:22 -0700203 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
reedd9544982014-09-09 18:46:22 -0700204 fFilter = NULL;
205 fLayer = NULL;
206 fTopLayer = NULL;
reed2ff1fce2014-12-11 07:07:37 -0800207 fMatrix.reset();
208 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700209
reedd9544982014-09-09 18:46:22 -0700210 // don't bother initializing fNext
211 inc_rec();
212 }
reed2ff1fce2014-12-11 07:07:37 -0800213 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700214 fFilter = SkSafeRef(prev.fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215 fLayer = NULL;
reedd9544982014-09-09 18:46:22 -0700216 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800217 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700218
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 // don't bother initializing fNext
220 inc_rec();
221 }
222 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000223 SkSafeUnref(fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 SkDELETE(fLayer);
225 dec_rec();
226 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227};
228
229class SkDrawIter : public SkDraw {
230public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000231 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000232 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000233 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 canvas->updateDeviceCMCache();
235
reedb679ca82015-04-07 04:40:48 -0700236 fClipStack = &canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000238 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 }
reed@google.com4b226022011-01-11 18:32:13 +0000240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 bool next() {
242 // skip over recs with empty clips
243 if (fSkipEmptyClips) {
244 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
245 fCurrLayer = fCurrLayer->fNext;
246 }
247 }
248
reed@google.comf68c5e22012-02-24 16:38:58 +0000249 const DeviceCM* rec = fCurrLayer;
250 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251
252 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000253 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
254 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 fDevice = rec->fDevice;
256 fBitmap = &fDevice->accessBitmap(true);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000258 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259
260 fCurrLayer = rec->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261 // fCurrLayer may be NULL now
reed@android.com199f1082009-06-10 02:12:47 +0000262
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 return true;
264 }
265 return false;
266 }
reed@google.com4b226022011-01-11 18:32:13 +0000267
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000268 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000269 int getX() const { return fDevice->getOrigin().x(); }
270 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 const SkMatrix& getMatrix() const { return *fMatrix; }
272 const SkRegion& getClip() const { return *fClip; }
273 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000274
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275private:
276 SkCanvas* fCanvas;
277 const DeviceCM* fCurrLayer;
278 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 SkBool8 fSkipEmptyClips;
280
281 typedef SkDraw INHERITED;
282};
283
284/////////////////////////////////////////////////////////////////////////////
285
286class AutoDrawLooper {
287public:
reed4a8126e2014-09-22 07:29:03 -0700288 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000289 bool skipLayerForImageFilter = false,
290 const SkRect* bounds = NULL) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000291 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700293 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000294 fSaveCount = canvas->getSaveCount();
reed@google.com8926b162012-03-23 15:36:36 +0000295 fDoClearImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000296 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297
reed1b110d62015-03-08 18:47:13 -0700298 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
reed@google.com8926b162012-03-23 15:36:36 +0000299 SkPaint tmp;
reed1b110d62015-03-08 18:47:13 -0700300 tmp.setImageFilter(fOrigPaint.getImageFilter());
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000301 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
reed76033be2015-03-14 10:54:31 -0700302 SkCanvas::kFullLayer_SaveLayerStrategy);
reed@google.com8926b162012-03-23 15:36:36 +0000303 // we'll clear the imageFilter for the actual draws in next(), so
304 // it will only be applied during the restore().
305 fDoClearImageFilter = true;
306 }
307
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000308 if (SkDrawLooper* looper = paint.getLooper()) {
309 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
310 looper->contextSize());
311 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000312 fIsSimple = false;
313 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000314 fLooperContext = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000315 // can we be marked as simple?
316 fIsSimple = !fFilter && !fDoClearImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000317 }
piotaixrb5fae932014-09-24 13:03:30 -0700318
reed4a8126e2014-09-22 07:29:03 -0700319 uint32_t oldFlags = paint.getFlags();
320 fNewPaintFlags = filter_paint_flags(props, oldFlags);
321 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reed1b110d62015-03-08 18:47:13 -0700322 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700323 paint->setFlags(fNewPaintFlags);
324 fPaint = paint;
325 // if we're not simple, doNext() will take care of calling setFlags()
326 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000327 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000328
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 ~AutoDrawLooper() {
reed@google.com8926b162012-03-23 15:36:36 +0000330 if (fDoClearImageFilter) {
331 fCanvas->internalRestore();
332 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000333 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000335
reed@google.com4e2b3d32011-04-07 14:18:59 +0000336 const SkPaint& paint() const {
337 SkASSERT(fPaint);
338 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000340
reed@google.com129ec222012-05-15 13:24:09 +0000341 bool next(SkDrawFilter::Type drawType) {
342 if (fDone) {
343 return false;
344 } else if (fIsSimple) {
345 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000346 return !fPaint->nothingToDraw();
347 } else {
348 return this->doNext(drawType);
349 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000350 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000351
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352private:
reed1b110d62015-03-08 18:47:13 -0700353 SkLazyPaint fLazyPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000354 SkCanvas* fCanvas;
355 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000356 SkDrawFilter* fFilter;
357 const SkPaint* fPaint;
358 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700359 uint32_t fNewPaintFlags;
reed@google.com8926b162012-03-23 15:36:36 +0000360 bool fDoClearImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000361 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000362 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000363 SkDrawLooper::Context* fLooperContext;
364 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000365
366 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367};
368
reed@google.com129ec222012-05-15 13:24:09 +0000369bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
reed@google.com632e1a22011-10-06 12:37:00 +0000370 fPaint = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000371 SkASSERT(!fIsSimple);
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000372 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000373
reed1b110d62015-03-08 18:47:13 -0700374 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700375 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000376
377 if (fDoClearImageFilter) {
378 paint->setImageFilter(NULL);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000379 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000380
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000381 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000382 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000383 return false;
384 }
385 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000386 if (!fFilter->filter(paint, drawType)) {
387 fDone = true;
388 return false;
389 }
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000390 if (NULL == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000391 // no looper means we only draw once
392 fDone = true;
393 }
394 }
395 fPaint = paint;
396
397 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000398 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000399 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000400 }
401
402 // call this after any possible paint modifiers
403 if (fPaint->nothingToDraw()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000404 fPaint = NULL;
405 return false;
406 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000407 return true;
408}
409
reed@android.com8a1c16f2008-12-17 15:59:43 +0000410////////// macros to place around the internal draw calls //////////////////
411
reed@google.com8926b162012-03-23 15:36:36 +0000412#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000413 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700414 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000415 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000416 SkDrawIter iter(this);
417
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000418#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000419 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700420 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000421 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000423
reed@google.com4e2b3d32011-04-07 14:18:59 +0000424#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000425
426////////////////////////////////////////////////////////////////////////////
427
reedd9544982014-09-09 18:46:22 -0700428SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
429 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
reed@google.comc0784db2013-12-13 21:16:12 +0000430 fCachedLocalClipBounds.setEmpty();
431 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000432 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000433 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700434 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800435 fSaveCount = 1;
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000436 fMetaData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437
438 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700439 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440
reedb679ca82015-04-07 04:40:48 -0700441 SkASSERT(sizeof(DeviceCM) <= sizeof(fBaseLayerStorage));
442 fMCRec->fLayer = (DeviceCM*)fBaseLayerStorage;
443 new (fBaseLayerStorage) DeviceCM(NULL, NULL, NULL, fConservativeRasterClip);
444
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446
reed@google.com97af1a62012-08-28 12:19:02 +0000447 fSurfaceBase = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000448
reedf92c8662014-08-18 08:02:43 -0700449 if (device) {
reedb2db8982014-11-13 12:41:02 -0800450 device->initForRootLayer(fProps.pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700451 if (device->forceConservativeRasterClip()) {
452 fConservativeRasterClip = true;
453 }
reedf92c8662014-08-18 08:02:43 -0700454 device->onAttachToCanvas(this);
455 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800456 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700457 }
458 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000459}
460
reed@google.comcde92112011-07-06 20:00:52 +0000461SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000462 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700463 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000464{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000465 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000466
reedd9544982014-09-09 18:46:22 -0700467 this->init(NULL, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000468}
469
reedd9544982014-09-09 18:46:22 -0700470static SkBitmap make_nopixels(int width, int height) {
471 SkBitmap bitmap;
472 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
473 return bitmap;
474}
475
476class SkNoPixelsBitmapDevice : public SkBitmapDevice {
477public:
reed78e27682014-11-19 08:04:34 -0800478 SkNoPixelsBitmapDevice(const SkIRect& bounds)
479 : INHERITED(make_nopixels(bounds.width(), bounds.height()))
480 {
481 this->setOrigin(bounds.x(), bounds.y());
482 }
reedd9544982014-09-09 18:46:22 -0700483
484private:
piotaixrb5fae932014-09-24 13:03:30 -0700485
reedd9544982014-09-09 18:46:22 -0700486 typedef SkBitmapDevice INHERITED;
487};
488
reed96a857e2015-01-25 10:33:58 -0800489SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000490 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800491 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000492{
493 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700494
reed78e27682014-11-19 08:04:34 -0800495 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
496 (SkIRect::MakeWH(width, height))), kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700497}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000498
reed78e27682014-11-19 08:04:34 -0800499SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700500 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700501 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700502{
503 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700504
reed78e27682014-11-19 08:04:34 -0800505 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds)), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700506}
507
reed4a8126e2014-09-22 07:29:03 -0700508SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700509 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700510 , fProps(SkSurfacePropsCopyOrDefault(props))
reedd9544982014-09-09 18:46:22 -0700511{
512 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700513
reedd9544982014-09-09 18:46:22 -0700514 this->init(device, flags);
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000515}
516
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000517SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000518 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700519 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000520{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700522
reedd9544982014-09-09 18:46:22 -0700523 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000524}
525
reed4a8126e2014-09-22 07:29:03 -0700526SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700527 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700528 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700529{
530 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700531
reed4a8126e2014-09-22 07:29:03 -0700532 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
533 this->init(device, kDefault_InitFlags);
534}
reed29c857d2014-09-21 10:25:07 -0700535
reed4a8126e2014-09-22 07:29:03 -0700536SkCanvas::SkCanvas(const SkBitmap& bitmap)
537 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
538 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
539{
540 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700541
reed4a8126e2014-09-22 07:29:03 -0700542 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
543 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544}
545
546SkCanvas::~SkCanvas() {
547 // free up the contents of our deque
548 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000549
reed@android.com8a1c16f2008-12-17 15:59:43 +0000550 this->internalRestore(); // restore the last, since we're going away
551
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000552 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000553
reed@android.com8a1c16f2008-12-17 15:59:43 +0000554 dec_canvas();
555}
556
reed@android.com8a1c16f2008-12-17 15:59:43 +0000557SkDrawFilter* SkCanvas::getDrawFilter() const {
558 return fMCRec->fFilter;
559}
560
561SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
562 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
563 return filter;
564}
565
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000566SkMetaData& SkCanvas::getMetaData() {
567 // metadata users are rare, so we lazily allocate it. If that changes we
568 // can decide to just make it a field in the device (rather than a ptr)
569 if (NULL == fMetaData) {
570 fMetaData = new SkMetaData;
571 }
572 return *fMetaData;
573}
574
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575///////////////////////////////////////////////////////////////////////////////
576
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000577void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000578 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000579 if (device) {
580 device->flush();
581 }
582}
583
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000584SkISize SkCanvas::getTopLayerSize() const {
585 SkBaseDevice* d = this->getTopDevice();
586 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
587}
588
589SkIPoint SkCanvas::getTopLayerOrigin() const {
590 SkBaseDevice* d = this->getTopDevice();
591 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
592}
593
594SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000595 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000596 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
597}
598
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000599SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000600 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000601 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000602 SkASSERT(rec && rec->fLayer);
603 return rec->fLayer->fDevice;
604}
605
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000606SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000607 if (updateMatrixClip) {
608 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
609 }
reed@google.com9266fed2011-03-30 00:18:03 +0000610 return fMCRec->fTopLayer->fDevice;
611}
612
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000613bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
614 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
615 return false;
616 }
617
618 bool weAllocated = false;
619 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700620 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000621 return false;
622 }
623 weAllocated = true;
624 }
625
626 SkBitmap bm(*bitmap);
627 bm.lockPixels();
628 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
629 return true;
630 }
631
632 if (weAllocated) {
633 bitmap->setPixelRef(NULL);
634 }
635 return false;
636}
reed@google.com51df9e32010-12-23 19:29:18 +0000637
bsalomon@google.comc6980972011-11-02 19:57:21 +0000638bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000639 SkIRect r = srcRect;
640 const SkISize size = this->getBaseLayerSize();
641 if (!r.intersect(0, 0, size.width(), size.height())) {
642 bitmap->reset();
643 return false;
644 }
645
reed84825042014-09-02 12:50:45 -0700646 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000647 // bitmap will already be reset.
648 return false;
649 }
650 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
651 bitmap->reset();
652 return false;
653 }
654 return true;
655}
656
reed96472de2014-12-10 09:53:42 -0800657bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000658 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000659 if (!device) {
660 return false;
661 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000662 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800663
reed96472de2014-12-10 09:53:42 -0800664 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
665 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000666 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000667 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000668
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000669 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800670 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000671}
672
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000673bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
674 if (bitmap.getTexture()) {
675 return false;
676 }
677 SkBitmap bm(bitmap);
678 bm.lockPixels();
679 if (bm.getPixels()) {
680 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
681 }
682 return false;
683}
684
685bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
686 int x, int y) {
687 switch (origInfo.colorType()) {
688 case kUnknown_SkColorType:
689 case kIndex_8_SkColorType:
690 return false;
691 default:
692 break;
693 }
694 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
695 return false;
696 }
697
698 const SkISize size = this->getBaseLayerSize();
699 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
700 if (!target.intersect(0, 0, size.width(), size.height())) {
701 return false;
702 }
703
704 SkBaseDevice* device = this->getDevice();
705 if (!device) {
706 return false;
707 }
708
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000709 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700710 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000711
712 // if x or y are negative, then we have to adjust pixels
713 if (x > 0) {
714 x = 0;
715 }
716 if (y > 0) {
717 y = 0;
718 }
719 // here x,y are either 0 or negative
720 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
721
reed4af35f32014-06-27 17:47:49 -0700722 // Tell our owning surface to bump its generation ID
723 this->predrawNotify();
724
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000725 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000726 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000727}
reed@google.com51df9e32010-12-23 19:29:18 +0000728
junov@google.com4370aed2012-01-18 16:21:08 +0000729SkCanvas* SkCanvas::canvasForDrawIter() {
730 return this;
731}
732
reed@android.com8a1c16f2008-12-17 15:59:43 +0000733//////////////////////////////////////////////////////////////////////////////
734
reed@android.com8a1c16f2008-12-17 15:59:43 +0000735void SkCanvas::updateDeviceCMCache() {
736 if (fDeviceCMDirty) {
737 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700738 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000739 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000740
reed@android.com8a1c16f2008-12-17 15:59:43 +0000741 if (NULL == layer->fNext) { // only one layer
reedb679ca82015-04-07 04:40:48 -0700742 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000743 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000744 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000745 do {
reedb679ca82015-04-07 04:40:48 -0700746 layer->updateMC(totalMatrix, clip, fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000747 } while ((layer = layer->fNext) != NULL);
748 }
749 fDeviceCMDirty = false;
750 }
751}
752
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753///////////////////////////////////////////////////////////////////////////////
754
reed2ff1fce2014-12-11 07:07:37 -0800755void SkCanvas::checkForDeferredSave() {
756 if (fMCRec->fDeferredSaveCount > 0) {
757 fMCRec->fDeferredSaveCount -= 1;
758 this->doSave();
759 }
760}
761
reedf0090cb2014-11-26 08:55:51 -0800762int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800763#ifdef SK_DEBUG
764 int count = 0;
765 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
766 for (;;) {
767 const MCRec* rec = (const MCRec*)iter.next();
768 if (!rec) {
769 break;
770 }
771 count += 1 + rec->fDeferredSaveCount;
772 }
773 SkASSERT(count == fSaveCount);
774#endif
775 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800776}
777
778int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800779 fSaveCount += 1;
780 fMCRec->fDeferredSaveCount += 1;
781 return this->getSaveCount() - 1; // return our prev value
782}
783
784void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800785 this->willSave();
reed2ff1fce2014-12-11 07:07:37 -0800786 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800787}
788
789void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800790 if (fMCRec->fDeferredSaveCount > 0) {
791 SkASSERT(fSaveCount > 1);
792 fSaveCount -= 1;
793 fMCRec->fDeferredSaveCount -= 1;
794 } else {
795 // check for underflow
796 if (fMCStack.count() > 1) {
797 this->willRestore();
798 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700799 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800800 this->internalRestore();
801 this->didRestore();
802 }
reedf0090cb2014-11-26 08:55:51 -0800803 }
804}
805
806void SkCanvas::restoreToCount(int count) {
807 // sanity check
808 if (count < 1) {
809 count = 1;
810 }
mtkleinf0f14112014-12-12 08:46:25 -0800811
reedf0090cb2014-11-26 08:55:51 -0800812 int n = this->getSaveCount() - count;
813 for (int i = 0; i < n; ++i) {
814 this->restore();
815 }
816}
817
reed2ff1fce2014-12-11 07:07:37 -0800818void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000819 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700820 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000822
reedb679ca82015-04-07 04:40:48 -0700823 fClipStack.save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824}
825
reed@android.com8a1c16f2008-12-17 15:59:43 +0000826static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000827#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000829#else
830 return true;
831#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000832}
833
junov@chromium.orga907ac32012-02-24 21:54:07 +0000834bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700835 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000836 SkIRect clipBounds;
837 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000838 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000839 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000840
reed96e657d2015-03-10 17:30:07 -0700841 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
842
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000843 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700844 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000845 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000846 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700847 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000848 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000849
reed96e657d2015-03-10 17:30:07 -0700850 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851 r.roundOut(&ir);
852 // early exit if the layer's bounds are clipped out
853 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000854 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700855 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700856 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000857 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000858 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000859 }
860 } else { // no user bounds, so just use the clip
861 ir = clipBounds;
862 }
reed180aec42015-03-11 10:39:04 -0700863 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000864
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000865 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -0700866 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -0700867 fCachedLocalClipBoundsDirty = true;
reedb679ca82015-04-07 04:40:48 -0700868 fClipStack.clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -0700869 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000870 }
871
872 if (intersection) {
873 *intersection = ir;
874 }
875 return true;
876}
877
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000878int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800879 if (gIgnoreSaveLayerBounds) {
880 bounds = NULL;
881 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000882 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -0700883 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700884 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800885 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000886}
887
reed2ff1fce2014-12-11 07:07:37 -0800888int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800889 if (gIgnoreSaveLayerBounds) {
890 bounds = NULL;
891 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000892 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -0700893 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700894 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800895 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000896}
897
reed2ff1fce2014-12-11 07:07:37 -0800898void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -0700899 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000900#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000901 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000902#endif
903
junov@chromium.orga907ac32012-02-24 21:54:07 +0000904 // do this before we create the layer. We don't call the public save() since
905 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -0800906 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000907
908 fDeviceCMDirty = true;
909
910 SkIRect ir;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000911 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -0800912 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000913 }
914
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000915 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
916 // the clipRectBounds() call above?
917 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -0800918 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000919 }
920
reed76033be2015-03-14 10:54:31 -0700921 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -0700922 SkPixelGeometry geo = fProps.pixelGeometry();
923 if (paint) {
reed76033be2015-03-14 10:54:31 -0700924 // TODO: perhaps add a query to filters so we might preserve opaqueness...
925 if (paint->getImageFilter() || paint->getColorFilter()) {
926 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -0700927 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +0000928 }
929 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000930 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
931 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000932
reedb2db8982014-11-13 12:41:02 -0800933 SkBaseDevice* device = this->getTopDevice();
934 if (NULL == device) {
935 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800936 return;
reed@google.com76dd2772012-01-05 21:15:07 +0000937 }
reedb2db8982014-11-13 12:41:02 -0800938
reed76033be2015-03-14 10:54:31 -0700939 SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed8dc0ccb2015-03-20 06:32:52 -0700940 device = device->onCreateDevice(SkBaseDevice::CreateInfo(info, usage, geo), paint);
bungeman@google.come25c6842011-08-17 14:53:54 +0000941 if (NULL == device) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800942 SkErrorInternals::SetError( kInternalError_SkError,
943 "Unable to create device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800944 return;
bungeman@google.come25c6842011-08-17 14:53:54 +0000945 }
bsalomon@google.come97f0852011-06-17 13:10:25 +0000946
reed@google.com6f8f2922011-03-04 22:27:10 +0000947 device->setOrigin(ir.fLeft, ir.fTop);
reed96e657d2015-03-10 17:30:07 -0700948 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000949 device->unref();
950
951 layer->fNext = fMCRec->fTopLayer;
952 fMCRec->fLayer = layer;
953 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000954}
955
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000956int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
957 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
958}
959
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
961 SaveFlags flags) {
962 if (0xFF == alpha) {
963 return this->saveLayer(bounds, NULL, flags);
964 } else {
965 SkPaint tmpPaint;
966 tmpPaint.setAlpha(alpha);
967 return this->saveLayer(bounds, &tmpPaint, flags);
968 }
969}
970
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971void SkCanvas::internalRestore() {
972 SkASSERT(fMCStack.count() != 0);
973
974 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +0000975 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976
reedb679ca82015-04-07 04:40:48 -0700977 fClipStack.restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +0000978
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000979 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980 DeviceCM* layer = fMCRec->fLayer; // may be null
981 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
982 fMCRec->fLayer = NULL;
983
984 // now do the normal restore()
985 fMCRec->~MCRec(); // balanced in save()
986 fMCStack.pop_back();
987 fMCRec = (MCRec*)fMCStack.back();
988
989 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
990 since if we're being recorded, we don't want to record this (the
991 recorder will have already recorded the restore).
992 */
bsalomon49f085d2014-09-05 13:34:00 -0700993 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000995 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +0000996 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
997 layer->fPaint);
998 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +0000999 fDeviceCMDirty = true;
reedb679ca82015-04-07 04:40:48 -07001000 SkDELETE(layer);
1001 } else {
1002 // we're at the root
1003 SkASSERT(layer == (void*)fBaseLayerStorage);
1004 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001005 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001006 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001007}
1008
reed4a8126e2014-09-22 07:29:03 -07001009SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1010 if (NULL == props) {
1011 props = &fProps;
1012 }
1013 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001014}
1015
reed4a8126e2014-09-22 07:29:03 -07001016SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001017 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001018 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001019}
1020
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001021SkImageInfo SkCanvas::imageInfo() const {
1022 SkBaseDevice* dev = this->getDevice();
1023 if (dev) {
1024 return dev->imageInfo();
1025 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001026 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001027 }
1028}
1029
1030const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1031 return this->onPeekPixels(info, rowBytes);
1032}
1033
1034const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1035 SkBaseDevice* dev = this->getDevice();
1036 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1037}
1038
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001039void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1040 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1041 if (pixels && origin) {
1042 *origin = this->getTopDevice(false)->getOrigin();
1043 }
1044 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001045}
1046
1047void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1048 SkBaseDevice* dev = this->getTopDevice();
1049 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1050}
1051
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001052SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1053 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1054 if (NULL == fAddr) {
1055 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001056 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001057 return; // failure, fAddr is NULL
1058 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001059 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1060 return; // failure, fAddr is NULL
1061 }
1062 fAddr = fBitmap.getPixels();
1063 fRowBytes = fBitmap.rowBytes();
1064 }
1065 SkASSERT(fAddr); // success
1066}
1067
1068bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1069 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001070 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001071 } else {
1072 bitmap->reset();
1073 return false;
1074 }
1075}
1076
reed@android.com8a1c16f2008-12-17 15:59:43 +00001077/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001078void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001079 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001080 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001081 return;
1082 }
1083
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001084 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001085 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001086 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001088
1089 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001090
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001091 SkRect storage;
1092 const SkRect* bounds = NULL;
1093 if (paint && paint->canComputeFastBounds()) {
1094 bitmap.getBounds(&storage);
1095 matrix.mapRect(&storage);
1096 bounds = &paint->computeFastBounds(storage, &storage);
1097 }
1098
1099 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001100
1101 while (iter.next()) {
1102 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1103 }
1104
1105 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001106}
1107
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001108void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed@google.com8926b162012-03-23 15:36:36 +00001109 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001110 SkPaint tmp;
1111 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001112 paint = &tmp;
1113 }
reed@google.com4b226022011-01-11 18:32:13 +00001114
reed@google.com8926b162012-03-23 15:36:36 +00001115 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001116 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001117 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001118 paint = &looper.paint();
1119 SkImageFilter* filter = paint->getImageFilter();
1120 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001121 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001122 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001123 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001124 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001125 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001126 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001127 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001128 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001129 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001130 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001131 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001132 SkPaint tmpUnfiltered(*paint);
1133 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001134 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1135 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001136 }
1137 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001138 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001139 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001140 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001141 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001142}
1143
reed41af9662015-01-05 07:49:08 -08001144void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001145 if (gTreatSpriteAsBitmap) {
1146 this->save();
1147 this->resetMatrix();
1148 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1149 this->restore();
1150 return;
1151 }
1152
danakj9881d632014-11-26 12:41:06 -08001153 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001154 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001155 return;
1156 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001157 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001158
reed@google.com8926b162012-03-23 15:36:36 +00001159 SkPaint tmp;
1160 if (NULL == paint) {
1161 paint = &tmp;
1162 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001163
reed@google.com8926b162012-03-23 15:36:36 +00001164 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001165
reed@google.com8926b162012-03-23 15:36:36 +00001166 while (iter.next()) {
1167 paint = &looper.paint();
1168 SkImageFilter* filter = paint->getImageFilter();
1169 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1170 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001171 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001172 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001173 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001174 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001175 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001176 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001177 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001178 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001179 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001180 SkPaint tmpUnfiltered(*paint);
1181 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001182 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001183 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001184 }
1185 } else {
1186 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1187 }
1188 }
1189 LOOPER_END
1190}
1191
reed@android.com8a1c16f2008-12-17 15:59:43 +00001192/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001193void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001194 SkMatrix m;
1195 m.setTranslate(dx, dy);
1196 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001197}
1198
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001199void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001200 SkMatrix m;
1201 m.setScale(sx, sy);
1202 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001203}
1204
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001205void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001206 SkMatrix m;
1207 m.setRotate(degrees);
1208 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001209}
1210
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001211void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001212 SkMatrix m;
1213 m.setSkew(sx, sy);
1214 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001215}
1216
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001217void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001218 if (matrix.isIdentity()) {
1219 return;
1220 }
1221
reed2ff1fce2014-12-11 07:07:37 -08001222 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001223 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001224 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001225 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001226
1227 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001228}
1229
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001231 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001232 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001233 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001234 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001235 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001236}
1237
reed@android.com8a1c16f2008-12-17 15:59:43 +00001238void SkCanvas::resetMatrix() {
1239 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001240
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241 matrix.reset();
1242 this->setMatrix(matrix);
1243}
1244
1245//////////////////////////////////////////////////////////////////////////////
1246
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001247void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001248 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001249 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1250 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001251}
1252
1253void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001254#ifdef SK_ENABLE_CLIP_QUICKREJECT
1255 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001256 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001257 return false;
1258 }
1259
reed@google.com3b3e8952012-08-16 20:53:31 +00001260 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001261 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001262 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001263
1264 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001265 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001266 }
1267 }
1268#endif
1269
reed@google.com5c3d1472011-02-22 19:12:23 +00001270 AutoValidateClip avc(this);
1271
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001273 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001274 if (!fAllowSoftClip) {
1275 edgeStyle = kHard_ClipEdgeStyle;
1276 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277
reed1f836ee2014-07-07 07:49:34 -07001278 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001279 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001280 // the matrix. This means we don't have to a) make a path, and b) tell
1281 // the region code to scan-convert the path, only to discover that it
1282 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001284
reed1f836ee2014-07-07 07:49:34 -07001285 fMCRec->fMatrix.mapRect(&r, rect);
reedb679ca82015-04-07 04:40:48 -07001286 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001287 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001289 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001290 // and clip against that, since it can handle any matrix. However, to
1291 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1292 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293 SkPath path;
1294
1295 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001296 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297 }
1298}
1299
reed73e714e2014-09-04 09:02:23 -07001300static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1301 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001302 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001303}
1304
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001305void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001306 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001307 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001308 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001309 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1310 } else {
1311 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001312 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001313}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001314
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001315void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001316 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001317 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001318 AutoValidateClip avc(this);
1319
1320 fDeviceCMDirty = true;
1321 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001322 if (!fAllowSoftClip) {
1323 edgeStyle = kHard_ClipEdgeStyle;
1324 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001325
reedb679ca82015-04-07 04:40:48 -07001326 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001327
1328 SkPath devPath;
1329 devPath.addRRect(transformedRRect);
1330
reed73e714e2014-09-04 09:02:23 -07001331 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001332 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001333 }
1334
1335 SkPath path;
1336 path.addRRect(rrect);
1337 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001338 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001339}
1340
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001341void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001342 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001343 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1344 SkRect r;
1345 if (!path.isInverseFillType() && path.isRect(&r)) {
1346 this->onClipRect(r, op, edgeStyle);
1347 } else {
1348 this->onClipPath(path, op, edgeStyle);
1349 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001350}
1351
1352void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001353#ifdef SK_ENABLE_CLIP_QUICKREJECT
1354 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001355 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001356 return false;
1357 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001358
reed@google.com3b3e8952012-08-16 20:53:31 +00001359 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001360 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001361 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001362
reed@google.comda17f752012-08-16 18:27:05 +00001363 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001364 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001365 }
1366 }
1367#endif
1368
reed@google.com5c3d1472011-02-22 19:12:23 +00001369 AutoValidateClip avc(this);
1370
reed@android.com8a1c16f2008-12-17 15:59:43 +00001371 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001372 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001373 if (!fAllowSoftClip) {
1374 edgeStyle = kHard_ClipEdgeStyle;
1375 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001376
1377 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001378 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001379
reed@google.comfe701122011-11-08 19:41:23 +00001380 // Check if the transfomation, or the original path itself
1381 // made us empty. Note this can also happen if we contained NaN
1382 // values. computing the bounds detects this, and will set our
1383 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1384 if (devPath.getBounds().isEmpty()) {
1385 // resetting the path will remove any NaN or other wanky values
1386 // that might upset our scan converter.
1387 devPath.reset();
1388 }
1389
reed@google.com5c3d1472011-02-22 19:12:23 +00001390 // if we called path.swap() we could avoid a deep copy of this path
reedb679ca82015-04-07 04:40:48 -07001391 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001392
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001393 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001394 bool clipIsAA = getClipStack()->asPath(&devPath);
1395 if (clipIsAA) {
1396 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001397 }
fmalita1a481fe2015-02-04 07:39:34 -08001398
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001399 op = SkRegion::kReplace_Op;
1400 }
1401
reed73e714e2014-09-04 09:02:23 -07001402 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001403}
1404
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001405void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001406 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001407 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001408}
1409
1410void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001411 AutoValidateClip avc(this);
1412
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001414 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415
reed@google.com5c3d1472011-02-22 19:12:23 +00001416 // todo: signal fClipStack that we have a region, and therefore (I guess)
1417 // we have to ignore it, and use the region directly?
reedb679ca82015-04-07 04:40:48 -07001418 fClipStack.clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001419
reed1f836ee2014-07-07 07:49:34 -07001420 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001421}
1422
reed@google.com819c9212011-02-23 18:56:55 +00001423#ifdef SK_DEBUG
1424void SkCanvas::validateClip() const {
1425 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001426 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001427 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001428 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001429 return;
1430 }
1431
reed@google.com819c9212011-02-23 18:56:55 +00001432 SkIRect ir;
1433 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001434 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001435
reedb679ca82015-04-07 04:40:48 -07001436 SkClipStack::B2TIter iter(fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001437 const SkClipStack::Element* element;
1438 while ((element = iter.next()) != NULL) {
1439 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001440 case SkClipStack::Element::kRect_Type:
1441 element->getRect().round(&ir);
1442 tmpClip.op(ir, element->getOp());
1443 break;
1444 case SkClipStack::Element::kEmpty_Type:
1445 tmpClip.setEmpty();
1446 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001447 default: {
1448 SkPath path;
1449 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001450 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001451 break;
1452 }
reed@google.com819c9212011-02-23 18:56:55 +00001453 }
1454 }
reed@google.com819c9212011-02-23 18:56:55 +00001455}
1456#endif
1457
reed@google.com90c07ea2012-04-13 13:50:27 +00001458void SkCanvas::replayClips(ClipVisitor* visitor) const {
reedb679ca82015-04-07 04:40:48 -07001459 SkClipStack::B2TIter iter(fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001460 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001461
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001462 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001463 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001464 }
1465}
1466
reed@google.com5c3d1472011-02-22 19:12:23 +00001467///////////////////////////////////////////////////////////////////////////////
1468
reed@google.com754de5f2014-02-24 19:38:20 +00001469bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001470 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001471}
1472
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001473bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001474 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001475}
1476
reed@google.com3b3e8952012-08-16 20:53:31 +00001477bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001478 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001479 return true;
1480
reed1f836ee2014-07-07 07:49:34 -07001481 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001482 return true;
1483 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001484
reed1f836ee2014-07-07 07:49:34 -07001485 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001486 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001487 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001488 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001489 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001490 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001491
reed@android.coma380ae42009-07-21 01:17:02 +00001492 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001493 // TODO: should we use | instead, or compare all 4 at once?
1494 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001495 return true;
1496 }
reed@google.comc0784db2013-12-13 21:16:12 +00001497 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001498 return true;
1499 }
1500 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001502}
1503
reed@google.com3b3e8952012-08-16 20:53:31 +00001504bool SkCanvas::quickReject(const SkPath& path) const {
1505 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001506}
1507
reed@google.com3b3e8952012-08-16 20:53:31 +00001508bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001509 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001510 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001511 return false;
1512 }
1513
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001514 SkMatrix inverse;
1515 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001516 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001517 if (bounds) {
1518 bounds->setEmpty();
1519 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001520 return false;
1521 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001522
bsalomon49f085d2014-09-05 13:34:00 -07001523 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001524 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001525 // adjust it outwards in case we are antialiasing
1526 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001527
reed@google.com8f4d2302013-12-17 16:44:46 +00001528 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1529 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001530 inverse.mapRect(bounds, r);
1531 }
1532 return true;
1533}
1534
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001535bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001536 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001537 if (clip.isEmpty()) {
1538 if (bounds) {
1539 bounds->setEmpty();
1540 }
1541 return false;
1542 }
1543
bsalomon49f085d2014-09-05 13:34:00 -07001544 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001545 *bounds = clip.getBounds();
1546 }
1547 return true;
1548}
1549
reed@android.com8a1c16f2008-12-17 15:59:43 +00001550const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001551 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001552}
1553
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001554const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001555 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001556}
1557
reed@google.com9c135db2014-03-12 18:28:35 +00001558GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1559 SkBaseDevice* dev = this->getTopDevice();
1560 return dev ? dev->accessRenderTarget() : NULL;
1561}
1562
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001563GrContext* SkCanvas::getGrContext() {
1564#if SK_SUPPORT_GPU
1565 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001566 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001567 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001568 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001569 return renderTarget->getContext();
1570 }
1571 }
1572#endif
1573
1574 return NULL;
1575
1576}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001577
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001578void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1579 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001580 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001581 if (outer.isEmpty()) {
1582 return;
1583 }
1584 if (inner.isEmpty()) {
1585 this->drawRRect(outer, paint);
1586 return;
1587 }
1588
1589 // We don't have this method (yet), but technically this is what we should
1590 // be able to assert...
1591 // SkASSERT(outer.contains(inner));
1592 //
1593 // For now at least check for containment of bounds
1594 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1595
1596 this->onDrawDRRect(outer, inner, paint);
1597}
1598
reed41af9662015-01-05 07:49:08 -08001599// These need to stop being virtual -- clients need to override the onDraw... versions
1600
1601void SkCanvas::drawPaint(const SkPaint& paint) {
1602 this->onDrawPaint(paint);
1603}
1604
1605void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1606 this->onDrawRect(r, paint);
1607}
1608
1609void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1610 this->onDrawOval(r, paint);
1611}
1612
1613void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1614 this->onDrawRRect(rrect, paint);
1615}
1616
1617void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1618 this->onDrawPoints(mode, count, pts, paint);
1619}
1620
1621void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1622 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1623 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1624 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1625 indices, indexCount, paint);
1626}
1627
1628void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1629 this->onDrawPath(path, paint);
1630}
1631
1632void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1633 this->onDrawImage(image, dx, dy, paint);
1634}
1635
1636void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1637 const SkPaint* paint) {
1638 this->onDrawImageRect(image, src, dst, paint);
1639}
1640
1641void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1642 this->onDrawBitmap(bitmap, dx, dy, paint);
1643}
1644
1645void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1646 const SkPaint* paint, DrawBitmapRectFlags flags) {
1647 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1648}
1649
1650void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1651 const SkPaint* paint) {
1652 this->onDrawBitmapNine(bitmap, center, dst, paint);
1653}
1654
1655void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
1656 this->onDrawSprite(bitmap, left, top, paint);
1657}
1658
reed@android.com8a1c16f2008-12-17 15:59:43 +00001659//////////////////////////////////////////////////////////////////////////////
1660// These are the virtual drawing methods
1661//////////////////////////////////////////////////////////////////////////////
1662
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001663void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001664 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001665 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1666 }
1667}
1668
reed41af9662015-01-05 07:49:08 -08001669void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001670 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001671 this->internalDrawPaint(paint);
1672}
1673
1674void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001675 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001676
1677 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001678 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001679 }
1680
reed@google.com4e2b3d32011-04-07 14:18:59 +00001681 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001682}
1683
reed41af9662015-01-05 07:49:08 -08001684void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1685 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001686 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001687 if ((long)count <= 0) {
1688 return;
1689 }
1690
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001691 SkRect r, storage;
1692 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001693 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001694 // special-case 2 points (common for drawing a single line)
1695 if (2 == count) {
1696 r.set(pts[0], pts[1]);
1697 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001698 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001699 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001700 bounds = &paint.computeFastStrokeBounds(r, &storage);
1701 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001702 return;
1703 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001704 }
reed@google.coma584aed2012-05-16 14:06:02 +00001705
reed@android.com8a1c16f2008-12-17 15:59:43 +00001706 SkASSERT(pts != NULL);
1707
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001708 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001709
reed@android.com8a1c16f2008-12-17 15:59:43 +00001710 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001711 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001712 }
reed@google.com4b226022011-01-11 18:32:13 +00001713
reed@google.com4e2b3d32011-04-07 14:18:59 +00001714 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001715}
1716
reed41af9662015-01-05 07:49:08 -08001717void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001718 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001719 SkRect storage;
1720 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001721 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001722 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1723 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1724 SkRect tmp(r);
1725 tmp.sort();
1726
1727 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001728 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001729 return;
1730 }
1731 }
reed@google.com4b226022011-01-11 18:32:13 +00001732
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001733 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001734
1735 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001736 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001737 }
1738
reed@google.com4e2b3d32011-04-07 14:18:59 +00001739 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001740}
1741
reed41af9662015-01-05 07:49:08 -08001742void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001743 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001744 SkRect storage;
1745 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001746 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001747 bounds = &paint.computeFastBounds(oval, &storage);
1748 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001749 return;
1750 }
1751 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001752
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001753 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001754
1755 while (iter.next()) {
1756 iter.fDevice->drawOval(iter, oval, looper.paint());
1757 }
1758
1759 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001760}
1761
reed41af9662015-01-05 07:49:08 -08001762void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001763 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001764 SkRect storage;
1765 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001766 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001767 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1768 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001769 return;
1770 }
1771 }
1772
1773 if (rrect.isRect()) {
1774 // call the non-virtual version
1775 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001776 return;
1777 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001778 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001779 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1780 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001781 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001782
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001783 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001784
1785 while (iter.next()) {
1786 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1787 }
1788
1789 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001790}
1791
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001792void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1793 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001794 SkRect storage;
1795 const SkRect* bounds = NULL;
1796 if (paint.canComputeFastBounds()) {
1797 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1798 if (this->quickReject(*bounds)) {
1799 return;
1800 }
1801 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001802
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001803 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001804
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001805 while (iter.next()) {
1806 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1807 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001808
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001809 LOOPER_END
1810}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001811
reed41af9662015-01-05 07:49:08 -08001812void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001813 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001814 if (!path.isFinite()) {
1815 return;
1816 }
1817
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001818 SkRect storage;
1819 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001820 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001821 const SkRect& pathBounds = path.getBounds();
1822 bounds = &paint.computeFastBounds(pathBounds, &storage);
1823 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001824 return;
1825 }
1826 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001827
1828 const SkRect& r = path.getBounds();
1829 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001830 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001831 this->internalDrawPaint(paint);
1832 }
1833 return;
1834 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001835
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001836 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001837
1838 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001839 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001840 }
1841
reed@google.com4e2b3d32011-04-07 14:18:59 +00001842 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001843}
1844
kkinnunena9baa652015-03-05 06:33:54 -08001845void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001846 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
kkinnunena9baa652015-03-05 06:33:54 -08001847 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001848}
1849
reed41af9662015-01-05 07:49:08 -08001850void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1851 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001852 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
kkinnunena9baa652015-03-05 06:33:54 -08001853 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001854}
1855
reed41af9662015-01-05 07:49:08 -08001856void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001857 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001858 SkDEBUGCODE(bitmap.validate();)
1859
reed@google.com3d608122011-11-21 15:16:16 +00001860 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001861 SkRect bounds = {
1862 x, y,
1863 x + SkIntToScalar(bitmap.width()),
1864 y + SkIntToScalar(bitmap.height())
1865 };
1866 if (paint) {
1867 (void)paint->computeFastBounds(bounds, &bounds);
1868 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001869 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001870 return;
1871 }
1872 }
reed@google.com4b226022011-01-11 18:32:13 +00001873
reed@android.com8a1c16f2008-12-17 15:59:43 +00001874 SkMatrix matrix;
1875 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001876 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001877}
1878
reed@google.com9987ec32011-09-07 11:57:52 +00001879// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00001880void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001881 const SkRect& dst, const SkPaint* paint,
1882 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001883 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001884 return;
1885 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001886
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001887 SkRect storage;
1888 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00001889 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001890 if (paint) {
1891 bounds = &paint->computeFastBounds(dst, &storage);
1892 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001893 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001894 return;
1895 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001896 }
reed@google.com3d608122011-11-21 15:16:16 +00001897
reed@google.com33535f32012-09-25 15:37:50 +00001898 SkLazyPaint lazy;
1899 if (NULL == paint) {
1900 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001901 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001902
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001903 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001904
reed@google.com33535f32012-09-25 15:37:50 +00001905 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001906 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00001907 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001908
reed@google.com33535f32012-09-25 15:37:50 +00001909 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001910}
1911
reed41af9662015-01-05 07:49:08 -08001912void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1913 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08001914 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00001915 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001916 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00001917}
1918
reed@google.com9987ec32011-09-07 11:57:52 +00001919void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1920 const SkIRect& center, const SkRect& dst,
1921 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001922 if (bitmap.drawsNothing()) {
1923 return;
1924 }
reed@google.com3d608122011-11-21 15:16:16 +00001925 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00001926 SkRect storage;
1927 const SkRect* bounds = &dst;
1928 if (paint) {
1929 bounds = &paint->computeFastBounds(dst, &storage);
1930 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001931 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001932 return;
1933 }
1934 }
1935
reed@google.com9987ec32011-09-07 11:57:52 +00001936 const int32_t w = bitmap.width();
1937 const int32_t h = bitmap.height();
1938
1939 SkIRect c = center;
1940 // pin center to the bounds of the bitmap
1941 c.fLeft = SkMax32(0, center.fLeft);
1942 c.fTop = SkMax32(0, center.fTop);
1943 c.fRight = SkPin32(center.fRight, c.fLeft, w);
1944 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1945
reed@google.com71121732012-09-18 15:14:33 +00001946 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001947 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00001948 };
1949 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001950 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00001951 };
reed@google.com9987ec32011-09-07 11:57:52 +00001952 SkScalar dstX[4] = {
1953 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
1954 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
1955 };
1956 SkScalar dstY[4] = {
1957 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
1958 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
1959 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001960
reed@google.com9987ec32011-09-07 11:57:52 +00001961 if (dstX[1] > dstX[2]) {
1962 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
1963 dstX[2] = dstX[1];
1964 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001965
reed@google.com9987ec32011-09-07 11:57:52 +00001966 if (dstY[1] > dstY[2]) {
1967 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
1968 dstY[2] = dstY[1];
1969 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001970
reed@google.com9987ec32011-09-07 11:57:52 +00001971 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00001972 SkRect s, d;
1973
reed@google.com9987ec32011-09-07 11:57:52 +00001974 s.fTop = srcY[y];
1975 s.fBottom = srcY[y+1];
1976 d.fTop = dstY[y];
1977 d.fBottom = dstY[y+1];
1978 for (int x = 0; x < 3; x++) {
1979 s.fLeft = srcX[x];
1980 s.fRight = srcX[x+1];
1981 d.fLeft = dstX[x];
1982 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001983 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00001984 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00001985 }
1986 }
1987}
1988
reed41af9662015-01-05 07:49:08 -08001989void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1990 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001991 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00001992 SkDEBUGCODE(bitmap.validate();)
1993
1994 // Need a device entry-point, so gpu can use a mesh
1995 this->internalDrawBitmapNine(bitmap, center, dst, paint);
1996}
1997
reed@google.comf67e4cf2011-03-15 20:56:58 +00001998class SkDeviceFilteredPaint {
1999public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002000 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002001 uint32_t filteredFlags = device->filterTextFlags(paint);
2002 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002003 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002004 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002005 fPaint = newPaint;
2006 } else {
2007 fPaint = &paint;
2008 }
2009 }
2010
reed@google.comf67e4cf2011-03-15 20:56:58 +00002011 const SkPaint& paint() const { return *fPaint; }
2012
2013private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002014 const SkPaint* fPaint;
2015 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002016};
2017
bungeman@google.com52c748b2011-08-22 21:30:43 +00002018void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2019 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002020 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002021 draw.fDevice->drawRect(draw, r, paint);
2022 } else {
2023 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002024 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002025 draw.fDevice->drawRect(draw, r, p);
2026 }
2027}
2028
2029void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2030 const char text[], size_t byteLength,
2031 SkScalar x, SkScalar y) {
2032 SkASSERT(byteLength == 0 || text != NULL);
2033
2034 // nothing to draw
2035 if (text == NULL || byteLength == 0 ||
2036 draw.fClip->isEmpty() ||
2037 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2038 return;
2039 }
2040
2041 SkScalar width = 0;
2042 SkPoint start;
2043
2044 start.set(0, 0); // to avoid warning
2045 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2046 SkPaint::kStrikeThruText_Flag)) {
2047 width = paint.measureText(text, byteLength);
2048
2049 SkScalar offsetX = 0;
2050 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2051 offsetX = SkScalarHalf(width);
2052 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2053 offsetX = width;
2054 }
2055 start.set(x - offsetX, y);
2056 }
2057
2058 if (0 == width) {
2059 return;
2060 }
2061
2062 uint32_t flags = paint.getFlags();
2063
2064 if (flags & (SkPaint::kUnderlineText_Flag |
2065 SkPaint::kStrikeThruText_Flag)) {
2066 SkScalar textSize = paint.getTextSize();
2067 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2068 SkRect r;
2069
2070 r.fLeft = start.fX;
2071 r.fRight = start.fX + width;
2072
2073 if (flags & SkPaint::kUnderlineText_Flag) {
2074 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2075 start.fY);
2076 r.fTop = offset;
2077 r.fBottom = offset + height;
2078 DrawRect(draw, paint, r, textSize);
2079 }
2080 if (flags & SkPaint::kStrikeThruText_Flag) {
2081 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2082 start.fY);
2083 r.fTop = offset;
2084 r.fBottom = offset + height;
2085 DrawRect(draw, paint, r, textSize);
2086 }
2087 }
2088}
2089
reed@google.come0d9ce82014-04-23 04:00:17 +00002090void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2091 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002092 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002093
2094 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002095 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002096 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002097 DrawTextDecorations(iter, dfp.paint(),
2098 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002099 }
2100
reed@google.com4e2b3d32011-04-07 14:18:59 +00002101 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002102}
2103
reed@google.come0d9ce82014-04-23 04:00:17 +00002104void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2105 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002106 SkPoint textOffset = SkPoint::Make(0, 0);
2107
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002108 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002109
reed@android.com8a1c16f2008-12-17 15:59:43 +00002110 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002111 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002112 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002113 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002114 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002115
reed@google.com4e2b3d32011-04-07 14:18:59 +00002116 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002117}
2118
reed@google.come0d9ce82014-04-23 04:00:17 +00002119void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2120 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002121
2122 SkPoint textOffset = SkPoint::Make(0, constY);
2123
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002124 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002125
reed@android.com8a1c16f2008-12-17 15:59:43 +00002126 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002127 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002128 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002129 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002130 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002131
reed@google.com4e2b3d32011-04-07 14:18:59 +00002132 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002133}
2134
reed@google.come0d9ce82014-04-23 04:00:17 +00002135void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2136 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002137 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002138
reed@android.com8a1c16f2008-12-17 15:59:43 +00002139 while (iter.next()) {
2140 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002141 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002142 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002143
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002144 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002145}
2146
fmalita00d5c2c2014-08-21 08:53:26 -07002147void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2148 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002149
fmalita85d5eb92015-03-04 11:20:12 -08002150 SkRect storage;
2151 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002152 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002153 storage = blob->bounds().makeOffset(x, y);
2154 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002155
fmalita85d5eb92015-03-04 11:20:12 -08002156 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002157 return;
2158 }
2159 }
2160
fmalita024f9962015-03-03 19:08:17 -08002161 // We cannot filter in the looper as we normally do, because the paint is
2162 // incomplete at this point (text-related attributes are embedded within blob run paints).
2163 SkDrawFilter* drawFilter = fMCRec->fFilter;
2164 fMCRec->fFilter = NULL;
2165
fmalita85d5eb92015-03-04 11:20:12 -08002166 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002167
fmalitaaa1b9122014-08-28 14:32:24 -07002168 while (iter.next()) {
2169 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002170 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002171 }
2172
fmalitaaa1b9122014-08-28 14:32:24 -07002173 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002174
2175 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002176}
2177
reed@google.come0d9ce82014-04-23 04:00:17 +00002178// These will become non-virtual, so they always call the (virtual) onDraw... method
2179void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2180 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002181 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002182 this->onDrawText(text, byteLength, x, y, paint);
2183}
2184void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2185 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002186 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002187 this->onDrawPosText(text, byteLength, pos, paint);
2188}
2189void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2190 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002191 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002192 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2193}
2194void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2195 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002196 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002197 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2198}
fmalita00d5c2c2014-08-21 08:53:26 -07002199void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2200 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002201 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002202 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002203 this->onDrawTextBlob(blob, x, y, paint);
2204 }
2205}
reed@google.come0d9ce82014-04-23 04:00:17 +00002206
reed41af9662015-01-05 07:49:08 -08002207void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2208 const SkPoint verts[], const SkPoint texs[],
2209 const SkColor colors[], SkXfermode* xmode,
2210 const uint16_t indices[], int indexCount,
2211 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002212 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002213 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002214
reed@android.com8a1c16f2008-12-17 15:59:43 +00002215 while (iter.next()) {
2216 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002217 colors, xmode, indices, indexCount,
2218 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002219 }
reed@google.com4b226022011-01-11 18:32:13 +00002220
reed@google.com4e2b3d32011-04-07 14:18:59 +00002221 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002222}
2223
dandovb3c9d1c2014-08-12 08:34:29 -07002224void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2225 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002226 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002227 if (NULL == cubics) {
2228 return;
2229 }
mtklein6cfa73a2014-08-13 13:33:49 -07002230
dandovecfff212014-08-04 10:02:00 -07002231 // Since a patch is always within the convex hull of the control points, we discard it when its
2232 // bounding rectangle is completely outside the current clip.
2233 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002234 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002235 if (this->quickReject(bounds)) {
2236 return;
2237 }
mtklein6cfa73a2014-08-13 13:33:49 -07002238
dandovb3c9d1c2014-08-12 08:34:29 -07002239 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2240}
2241
2242void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2243 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2244
dandovecfff212014-08-04 10:02:00 -07002245 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002246
dandovecfff212014-08-04 10:02:00 -07002247 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002248 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002249 }
mtklein6cfa73a2014-08-13 13:33:49 -07002250
dandovecfff212014-08-04 10:02:00 -07002251 LOOPER_END
2252}
2253
reed3cb38402015-02-06 08:36:15 -08002254void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002255 if (dr && !this->quickReject(dr->getBounds())) {
2256 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002257 }
2258}
2259
reed3cb38402015-02-06 08:36:15 -08002260void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002261 dr->draw(this);
2262}
2263
reed@android.com8a1c16f2008-12-17 15:59:43 +00002264//////////////////////////////////////////////////////////////////////////////
2265// These methods are NOT virtual, and therefore must call back into virtual
2266// methods, rather than actually drawing themselves.
2267//////////////////////////////////////////////////////////////////////////////
2268
2269void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002270 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002271 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002272 SkPaint paint;
2273
2274 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002275 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002276 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002277 }
2278 this->drawPaint(paint);
2279}
2280
reed@android.com845fdac2009-06-23 03:01:32 +00002281void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002282 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002283 SkPaint paint;
2284
2285 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002286 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002287 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002288 }
2289 this->drawPaint(paint);
2290}
2291
2292void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002293 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002294 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002295
reed@android.com8a1c16f2008-12-17 15:59:43 +00002296 pt.set(x, y);
2297 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2298}
2299
2300void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002301 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302 SkPoint pt;
2303 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002304
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305 pt.set(x, y);
2306 paint.setColor(color);
2307 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2308}
2309
2310void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2311 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002312 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002313 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002314
reed@android.com8a1c16f2008-12-17 15:59:43 +00002315 pts[0].set(x0, y0);
2316 pts[1].set(x1, y1);
2317 this->drawPoints(kLines_PointMode, 2, pts, paint);
2318}
2319
2320void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2321 SkScalar right, SkScalar bottom,
2322 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002323 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324 SkRect r;
2325
2326 r.set(left, top, right, bottom);
2327 this->drawRect(r, paint);
2328}
2329
2330void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2331 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002332 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002333 if (radius < 0) {
2334 radius = 0;
2335 }
2336
2337 SkRect r;
2338 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002339 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002340}
2341
2342void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2343 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002344 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002345 if (rx > 0 && ry > 0) {
2346 if (paint.canComputeFastBounds()) {
2347 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002348 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002349 return;
2350 }
2351 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002352 SkRRect rrect;
2353 rrect.setRectXY(r, rx, ry);
2354 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002355 } else {
2356 this->drawRect(r, paint);
2357 }
2358}
2359
reed@android.com8a1c16f2008-12-17 15:59:43 +00002360void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2361 SkScalar sweepAngle, bool useCenter,
2362 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002363 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002364 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2365 this->drawOval(oval, paint);
2366 } else {
2367 SkPath path;
2368 if (useCenter) {
2369 path.moveTo(oval.centerX(), oval.centerY());
2370 }
2371 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2372 if (useCenter) {
2373 path.close();
2374 }
2375 this->drawPath(path, paint);
2376 }
2377}
2378
2379void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2380 const SkPath& path, SkScalar hOffset,
2381 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002382 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002383 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002384
reed@android.com8a1c16f2008-12-17 15:59:43 +00002385 matrix.setTranslate(hOffset, vOffset);
2386 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2387}
2388
reed@android.comf76bacf2009-05-13 14:00:33 +00002389///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002390void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002391 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002392 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002393 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002394 }
2395}
2396
reedd5fa1a42014-08-09 11:08:05 -07002397void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002398 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002399 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002400 if (matrix && matrix->isIdentity()) {
2401 matrix = NULL;
2402 }
2403 this->onDrawPicture(picture, matrix, paint);
2404 }
2405}
robertphillips9b14f262014-06-04 05:40:44 -07002406
reedd5fa1a42014-08-09 11:08:05 -07002407void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2408 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002409 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002410 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002411 // Canvas has to first give the device the opportunity to render
2412 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002413 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002414 return; // the device has rendered the entire picture
2415 }
2416 }
2417
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002418 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002419
robertphillipsc5ba71d2014-09-04 08:42:50 -07002420 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002421}
2422
reed@android.com8a1c16f2008-12-17 15:59:43 +00002423///////////////////////////////////////////////////////////////////////////////
2424///////////////////////////////////////////////////////////////////////////////
2425
2426SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002427 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002428
2429 SkASSERT(canvas);
2430
2431 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2432 fDone = !fImpl->next();
2433}
2434
2435SkCanvas::LayerIter::~LayerIter() {
2436 fImpl->~SkDrawIter();
2437}
2438
2439void SkCanvas::LayerIter::next() {
2440 fDone = !fImpl->next();
2441}
2442
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002443SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002444 return fImpl->getDevice();
2445}
2446
2447const SkMatrix& SkCanvas::LayerIter::matrix() const {
2448 return fImpl->getMatrix();
2449}
2450
2451const SkPaint& SkCanvas::LayerIter::paint() const {
2452 const SkPaint* paint = fImpl->getPaint();
2453 if (NULL == paint) {
2454 paint = &fDefaultPaint;
2455 }
2456 return *paint;
2457}
2458
2459const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2460int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2461int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002462
2463///////////////////////////////////////////////////////////////////////////////
2464
fmalitac3b589a2014-06-05 12:40:07 -07002465SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002466
2467///////////////////////////////////////////////////////////////////////////////
2468
2469static bool supported_for_raster_canvas(const SkImageInfo& info) {
2470 switch (info.alphaType()) {
2471 case kPremul_SkAlphaType:
2472 case kOpaque_SkAlphaType:
2473 break;
2474 default:
2475 return false;
2476 }
2477
2478 switch (info.colorType()) {
2479 case kAlpha_8_SkColorType:
2480 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002481 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002482 break;
2483 default:
2484 return false;
2485 }
2486
2487 return true;
2488}
2489
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002490SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2491 if (!supported_for_raster_canvas(info)) {
2492 return NULL;
2493 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002494
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002495 SkBitmap bitmap;
2496 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2497 return NULL;
2498 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002499 return SkNEW_ARGS(SkCanvas, (bitmap));
2500}
reedd5fa1a42014-08-09 11:08:05 -07002501
2502///////////////////////////////////////////////////////////////////////////////
2503
2504SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002505 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002506 : fCanvas(canvas)
2507 , fSaveCount(canvas->getSaveCount())
2508{
bsalomon49f085d2014-09-05 13:34:00 -07002509 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002510 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002511 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002512 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002513 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002514 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002515 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002516 canvas->save();
2517 }
mtklein6cfa73a2014-08-13 13:33:49 -07002518
bsalomon49f085d2014-09-05 13:34:00 -07002519 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002520 canvas->concat(*matrix);
2521 }
2522}
2523
2524SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2525 fCanvas->restoreToCount(fSaveCount);
2526}