blob: 8426f090ec5949653ab516ffca3f7d33a317c338 [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
joshualittde358a92015-02-05 08:19:35 -0800236 fClipStack = canvas->fClipStack.get();
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
reed96e657d2015-03-10 17:30:07 -0700441 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, NULL, NULL, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443
reed@google.com97af1a62012-08-28 12:19:02 +0000444 fSurfaceBase = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000445
joshualittde358a92015-02-05 08:19:35 -0800446 fClipStack.reset(SkNEW(SkClipStack));
447
reedf92c8662014-08-18 08:02:43 -0700448 if (device) {
reedb2db8982014-11-13 12:41:02 -0800449 device->initForRootLayer(fProps.pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700450 if (device->forceConservativeRasterClip()) {
451 fConservativeRasterClip = true;
452 }
reedf92c8662014-08-18 08:02:43 -0700453 device->onAttachToCanvas(this);
454 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800455 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700456 }
457 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000458}
459
reed@google.comcde92112011-07-06 20:00:52 +0000460SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000461 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700462 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000463{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000464 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000465
reedd9544982014-09-09 18:46:22 -0700466 this->init(NULL, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000467}
468
reedd9544982014-09-09 18:46:22 -0700469static SkBitmap make_nopixels(int width, int height) {
470 SkBitmap bitmap;
471 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
472 return bitmap;
473}
474
475class SkNoPixelsBitmapDevice : public SkBitmapDevice {
476public:
reed78e27682014-11-19 08:04:34 -0800477 SkNoPixelsBitmapDevice(const SkIRect& bounds)
478 : INHERITED(make_nopixels(bounds.width(), bounds.height()))
479 {
480 this->setOrigin(bounds.x(), bounds.y());
481 }
reedd9544982014-09-09 18:46:22 -0700482
483private:
piotaixrb5fae932014-09-24 13:03:30 -0700484
reedd9544982014-09-09 18:46:22 -0700485 typedef SkBitmapDevice INHERITED;
486};
487
reed96a857e2015-01-25 10:33:58 -0800488SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000489 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800490 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000491{
492 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700493
reed78e27682014-11-19 08:04:34 -0800494 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
495 (SkIRect::MakeWH(width, height))), kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700496}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000497
reed78e27682014-11-19 08:04:34 -0800498SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700499 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700500 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700501{
502 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700503
reed78e27682014-11-19 08:04:34 -0800504 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds)), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700505}
506
reed4a8126e2014-09-22 07:29:03 -0700507SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700508 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700509 , fProps(SkSurfacePropsCopyOrDefault(props))
reedd9544982014-09-09 18:46:22 -0700510{
511 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700512
reedd9544982014-09-09 18:46:22 -0700513 this->init(device, flags);
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000514}
515
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000516SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000517 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700518 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000519{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000520 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700521
reedd9544982014-09-09 18:46:22 -0700522 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523}
524
reed4a8126e2014-09-22 07:29:03 -0700525SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700526 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700527 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700528{
529 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700530
reed4a8126e2014-09-22 07:29:03 -0700531 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
532 this->init(device, kDefault_InitFlags);
533}
reed29c857d2014-09-21 10:25:07 -0700534
reed4a8126e2014-09-22 07:29:03 -0700535SkCanvas::SkCanvas(const SkBitmap& bitmap)
536 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
537 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
538{
539 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700540
reed4a8126e2014-09-22 07:29:03 -0700541 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
542 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000543}
544
545SkCanvas::~SkCanvas() {
546 // free up the contents of our deque
547 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000548
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549 this->internalRestore(); // restore the last, since we're going away
550
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000551 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000552
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553 dec_canvas();
554}
555
reed@android.com8a1c16f2008-12-17 15:59:43 +0000556SkDrawFilter* SkCanvas::getDrawFilter() const {
557 return fMCRec->fFilter;
558}
559
560SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
561 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
562 return filter;
563}
564
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000565SkMetaData& SkCanvas::getMetaData() {
566 // metadata users are rare, so we lazily allocate it. If that changes we
567 // can decide to just make it a field in the device (rather than a ptr)
568 if (NULL == fMetaData) {
569 fMetaData = new SkMetaData;
570 }
571 return *fMetaData;
572}
573
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574///////////////////////////////////////////////////////////////////////////////
575
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000576void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000577 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000578 if (device) {
579 device->flush();
580 }
581}
582
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000583SkISize SkCanvas::getTopLayerSize() const {
584 SkBaseDevice* d = this->getTopDevice();
585 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
586}
587
588SkIPoint SkCanvas::getTopLayerOrigin() const {
589 SkBaseDevice* d = this->getTopDevice();
590 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
591}
592
593SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000594 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000595 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
596}
597
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000598SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000599 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000600 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601 SkASSERT(rec && rec->fLayer);
602 return rec->fLayer->fDevice;
603}
604
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000605SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000606 if (updateMatrixClip) {
607 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
608 }
reed@google.com9266fed2011-03-30 00:18:03 +0000609 return fMCRec->fTopLayer->fDevice;
610}
611
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000612bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
613 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
614 return false;
615 }
616
617 bool weAllocated = false;
618 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700619 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000620 return false;
621 }
622 weAllocated = true;
623 }
624
625 SkBitmap bm(*bitmap);
626 bm.lockPixels();
627 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
628 return true;
629 }
630
631 if (weAllocated) {
632 bitmap->setPixelRef(NULL);
633 }
634 return false;
635}
reed@google.com51df9e32010-12-23 19:29:18 +0000636
bsalomon@google.comc6980972011-11-02 19:57:21 +0000637bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000638 SkIRect r = srcRect;
639 const SkISize size = this->getBaseLayerSize();
640 if (!r.intersect(0, 0, size.width(), size.height())) {
641 bitmap->reset();
642 return false;
643 }
644
reed84825042014-09-02 12:50:45 -0700645 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000646 // bitmap will already be reset.
647 return false;
648 }
649 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
650 bitmap->reset();
651 return false;
652 }
653 return true;
654}
655
reed96472de2014-12-10 09:53:42 -0800656bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000657 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000658 if (!device) {
659 return false;
660 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000661 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800662
reed96472de2014-12-10 09:53:42 -0800663 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
664 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000665 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000666 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000667
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000668 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800669 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000670}
671
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000672bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
673 if (bitmap.getTexture()) {
674 return false;
675 }
676 SkBitmap bm(bitmap);
677 bm.lockPixels();
678 if (bm.getPixels()) {
679 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
680 }
681 return false;
682}
683
684bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
685 int x, int y) {
686 switch (origInfo.colorType()) {
687 case kUnknown_SkColorType:
688 case kIndex_8_SkColorType:
689 return false;
690 default:
691 break;
692 }
693 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
694 return false;
695 }
696
697 const SkISize size = this->getBaseLayerSize();
698 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
699 if (!target.intersect(0, 0, size.width(), size.height())) {
700 return false;
701 }
702
703 SkBaseDevice* device = this->getDevice();
704 if (!device) {
705 return false;
706 }
707
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000708 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700709 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000710
711 // if x or y are negative, then we have to adjust pixels
712 if (x > 0) {
713 x = 0;
714 }
715 if (y > 0) {
716 y = 0;
717 }
718 // here x,y are either 0 or negative
719 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
720
reed4af35f32014-06-27 17:47:49 -0700721 // Tell our owning surface to bump its generation ID
722 this->predrawNotify();
723
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000724 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000725 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000726}
reed@google.com51df9e32010-12-23 19:29:18 +0000727
junov@google.com4370aed2012-01-18 16:21:08 +0000728SkCanvas* SkCanvas::canvasForDrawIter() {
729 return this;
730}
731
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732//////////////////////////////////////////////////////////////////////////////
733
reed@android.com8a1c16f2008-12-17 15:59:43 +0000734void SkCanvas::updateDeviceCMCache() {
735 if (fDeviceCMDirty) {
736 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700737 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000739
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740 if (NULL == layer->fNext) { // only one layer
joshualittde358a92015-02-05 08:19:35 -0800741 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000743 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000744 do {
joshualittde358a92015-02-05 08:19:35 -0800745 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746 } while ((layer = layer->fNext) != NULL);
747 }
748 fDeviceCMDirty = false;
749 }
750}
751
reed@android.com8a1c16f2008-12-17 15:59:43 +0000752///////////////////////////////////////////////////////////////////////////////
753
reed2ff1fce2014-12-11 07:07:37 -0800754void SkCanvas::checkForDeferredSave() {
755 if (fMCRec->fDeferredSaveCount > 0) {
756 fMCRec->fDeferredSaveCount -= 1;
757 this->doSave();
758 }
759}
760
reedf0090cb2014-11-26 08:55:51 -0800761int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800762#ifdef SK_DEBUG
763 int count = 0;
764 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
765 for (;;) {
766 const MCRec* rec = (const MCRec*)iter.next();
767 if (!rec) {
768 break;
769 }
770 count += 1 + rec->fDeferredSaveCount;
771 }
772 SkASSERT(count == fSaveCount);
773#endif
774 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800775}
776
777int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800778 fSaveCount += 1;
779 fMCRec->fDeferredSaveCount += 1;
780 return this->getSaveCount() - 1; // return our prev value
781}
782
783void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800784 this->willSave();
reed2ff1fce2014-12-11 07:07:37 -0800785 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800786}
787
788void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800789 if (fMCRec->fDeferredSaveCount > 0) {
790 SkASSERT(fSaveCount > 1);
791 fSaveCount -= 1;
792 fMCRec->fDeferredSaveCount -= 1;
793 } else {
794 // check for underflow
795 if (fMCStack.count() > 1) {
796 this->willRestore();
797 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700798 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800799 this->internalRestore();
800 this->didRestore();
801 }
reedf0090cb2014-11-26 08:55:51 -0800802 }
803}
804
805void SkCanvas::restoreToCount(int count) {
806 // sanity check
807 if (count < 1) {
808 count = 1;
809 }
mtkleinf0f14112014-12-12 08:46:25 -0800810
reedf0090cb2014-11-26 08:55:51 -0800811 int n = this->getSaveCount() - count;
812 for (int i = 0; i < n; ++i) {
813 this->restore();
814 }
815}
816
reed2ff1fce2014-12-11 07:07:37 -0800817void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000818 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700819 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000820 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000821
joshualittde358a92015-02-05 08:19:35 -0800822 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823}
824
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000826#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000828#else
829 return true;
830#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831}
832
junov@chromium.orga907ac32012-02-24 21:54:07 +0000833bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700834 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000835 SkIRect clipBounds;
836 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000837 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000838 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000839
reed96e657d2015-03-10 17:30:07 -0700840 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
841
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000842 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700843 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000844 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000845 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700846 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000847 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000848
reed96e657d2015-03-10 17:30:07 -0700849 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850 r.roundOut(&ir);
851 // early exit if the layer's bounds are clipped out
852 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000853 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700854 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700855 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000856 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000857 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000858 }
859 } else { // no user bounds, so just use the clip
860 ir = clipBounds;
861 }
reed180aec42015-03-11 10:39:04 -0700862 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000863
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000864 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -0700865 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -0700866 fCachedLocalClipBoundsDirty = true;
reed180aec42015-03-11 10:39:04 -0700867 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
868 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000869 }
870
871 if (intersection) {
872 *intersection = ir;
873 }
874 return true;
875}
876
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000877int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800878 if (gIgnoreSaveLayerBounds) {
879 bounds = NULL;
880 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000881 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -0700882 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700883 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800884 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000885}
886
reed2ff1fce2014-12-11 07:07:37 -0800887int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800888 if (gIgnoreSaveLayerBounds) {
889 bounds = NULL;
890 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000891 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -0700892 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700893 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800894 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000895}
896
reed2ff1fce2014-12-11 07:07:37 -0800897void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -0700898 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000899#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000900 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000901#endif
902
junov@chromium.orga907ac32012-02-24 21:54:07 +0000903 // do this before we create the layer. We don't call the public save() since
904 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -0800905 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000906
907 fDeviceCMDirty = true;
908
909 SkIRect ir;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000910 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -0800911 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000912 }
913
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000914 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
915 // the clipRectBounds() call above?
916 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -0800917 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000918 }
919
reed76033be2015-03-14 10:54:31 -0700920 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -0700921 SkPixelGeometry geo = fProps.pixelGeometry();
922 if (paint) {
reed76033be2015-03-14 10:54:31 -0700923 // TODO: perhaps add a query to filters so we might preserve opaqueness...
924 if (paint->getImageFilter() || paint->getColorFilter()) {
925 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -0700926 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +0000927 }
928 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000929 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
930 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000931
reedb2db8982014-11-13 12:41:02 -0800932 SkBaseDevice* device = this->getTopDevice();
933 if (NULL == device) {
934 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800935 return;
reed@google.com76dd2772012-01-05 21:15:07 +0000936 }
reedb2db8982014-11-13 12:41:02 -0800937
reed76033be2015-03-14 10:54:31 -0700938 SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
939#if 1
940 // this seems needed for current GMs, but makes us draw slower on the GPU
941 // Related to https://code.google.com/p/skia/issues/detail?id=3519 ?
942 //
reedb2db8982014-11-13 12:41:02 -0800943 if (paint && paint->getImageFilter()) {
reed76033be2015-03-14 10:54:31 -0700944 usage = SkBaseDevice::kPossible_TileUsage;
reedb2db8982014-11-13 12:41:02 -0800945 }
reed76033be2015-03-14 10:54:31 -0700946#endif
reed8dc0ccb2015-03-20 06:32:52 -0700947 device = device->onCreateDevice(SkBaseDevice::CreateInfo(info, usage, geo), paint);
bungeman@google.come25c6842011-08-17 14:53:54 +0000948 if (NULL == device) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800949 SkErrorInternals::SetError( kInternalError_SkError,
950 "Unable to create device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800951 return;
bungeman@google.come25c6842011-08-17 14:53:54 +0000952 }
bsalomon@google.come97f0852011-06-17 13:10:25 +0000953
reed@google.com6f8f2922011-03-04 22:27:10 +0000954 device->setOrigin(ir.fLeft, ir.fTop);
reed96e657d2015-03-10 17:30:07 -0700955 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000956 device->unref();
957
958 layer->fNext = fMCRec->fTopLayer;
959 fMCRec->fLayer = layer;
960 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000961}
962
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000963int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
964 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
965}
966
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
968 SaveFlags flags) {
969 if (0xFF == alpha) {
970 return this->saveLayer(bounds, NULL, flags);
971 } else {
972 SkPaint tmpPaint;
973 tmpPaint.setAlpha(alpha);
974 return this->saveLayer(bounds, &tmpPaint, flags);
975 }
976}
977
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978void SkCanvas::internalRestore() {
979 SkASSERT(fMCStack.count() != 0);
980
981 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +0000982 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000983
joshualittde358a92015-02-05 08:19:35 -0800984 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +0000985
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000986 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987 DeviceCM* layer = fMCRec->fLayer; // may be null
988 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
989 fMCRec->fLayer = NULL;
990
991 // now do the normal restore()
992 fMCRec->~MCRec(); // balanced in save()
993 fMCStack.pop_back();
994 fMCRec = (MCRec*)fMCStack.back();
995
996 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
997 since if we're being recorded, we don't want to record this (the
998 recorder will have already recorded the restore).
999 */
bsalomon49f085d2014-09-05 13:34:00 -07001000 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001001 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001002 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001003 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1004 layer->fPaint);
1005 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001006 fDeviceCMDirty = true;
1007 }
1008 SkDELETE(layer);
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001009 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001010}
1011
reed4a8126e2014-09-22 07:29:03 -07001012SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1013 if (NULL == props) {
1014 props = &fProps;
1015 }
1016 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001017}
1018
reed4a8126e2014-09-22 07:29:03 -07001019SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001020 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001021 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001022}
1023
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001024SkImageInfo SkCanvas::imageInfo() const {
1025 SkBaseDevice* dev = this->getDevice();
1026 if (dev) {
1027 return dev->imageInfo();
1028 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001029 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001030 }
1031}
1032
1033const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1034 return this->onPeekPixels(info, rowBytes);
1035}
1036
1037const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1038 SkBaseDevice* dev = this->getDevice();
1039 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1040}
1041
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001042void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1043 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1044 if (pixels && origin) {
1045 *origin = this->getTopDevice(false)->getOrigin();
1046 }
1047 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001048}
1049
1050void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1051 SkBaseDevice* dev = this->getTopDevice();
1052 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1053}
1054
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001055SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1056 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1057 if (NULL == fAddr) {
1058 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001059 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001060 return; // failure, fAddr is NULL
1061 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001062 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1063 return; // failure, fAddr is NULL
1064 }
1065 fAddr = fBitmap.getPixels();
1066 fRowBytes = fBitmap.rowBytes();
1067 }
1068 SkASSERT(fAddr); // success
1069}
1070
1071bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1072 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001073 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001074 } else {
1075 bitmap->reset();
1076 return false;
1077 }
1078}
1079
reed@android.com8a1c16f2008-12-17 15:59:43 +00001080/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001081void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001082 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001083 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001084 return;
1085 }
1086
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001087 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001089 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001091
1092 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001093
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001094 SkRect storage;
1095 const SkRect* bounds = NULL;
1096 if (paint && paint->canComputeFastBounds()) {
1097 bitmap.getBounds(&storage);
1098 matrix.mapRect(&storage);
1099 bounds = &paint->computeFastBounds(storage, &storage);
1100 }
1101
1102 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001103
1104 while (iter.next()) {
1105 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1106 }
1107
1108 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001109}
1110
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001111void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed@google.com8926b162012-03-23 15:36:36 +00001112 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001113 SkPaint tmp;
1114 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001115 paint = &tmp;
1116 }
reed@google.com4b226022011-01-11 18:32:13 +00001117
reed@google.com8926b162012-03-23 15:36:36 +00001118 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001119 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001120 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001121 paint = &looper.paint();
1122 SkImageFilter* filter = paint->getImageFilter();
1123 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001124 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001125 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001126 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001127 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001128 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001129 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001130 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001131 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001132 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001133 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001134 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001135 SkPaint tmpUnfiltered(*paint);
1136 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001137 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1138 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001139 }
1140 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001141 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001142 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001143 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001144 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145}
1146
reed41af9662015-01-05 07:49:08 -08001147void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001148 if (gTreatSpriteAsBitmap) {
1149 this->save();
1150 this->resetMatrix();
1151 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1152 this->restore();
1153 return;
1154 }
1155
danakj9881d632014-11-26 12:41:06 -08001156 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001157 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001158 return;
1159 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001160 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001161
reed@google.com8926b162012-03-23 15:36:36 +00001162 SkPaint tmp;
1163 if (NULL == paint) {
1164 paint = &tmp;
1165 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001166
reed@google.com8926b162012-03-23 15:36:36 +00001167 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001168
reed@google.com8926b162012-03-23 15:36:36 +00001169 while (iter.next()) {
1170 paint = &looper.paint();
1171 SkImageFilter* filter = paint->getImageFilter();
1172 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1173 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001174 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001175 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001176 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001177 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001178 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001179 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001180 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001181 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001182 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001183 SkPaint tmpUnfiltered(*paint);
1184 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001185 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001186 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001187 }
1188 } else {
1189 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1190 }
1191 }
1192 LOOPER_END
1193}
1194
reed@android.com8a1c16f2008-12-17 15:59:43 +00001195/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001196void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001197 SkMatrix m;
1198 m.setTranslate(dx, dy);
1199 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001200}
1201
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001202void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001203 SkMatrix m;
1204 m.setScale(sx, sy);
1205 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001206}
1207
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001208void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001209 SkMatrix m;
1210 m.setRotate(degrees);
1211 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212}
1213
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001214void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001215 SkMatrix m;
1216 m.setSkew(sx, sy);
1217 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001218}
1219
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001220void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001221 if (matrix.isIdentity()) {
1222 return;
1223 }
1224
reed2ff1fce2014-12-11 07:07:37 -08001225 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001226 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001227 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001228 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001229
1230 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001231}
1232
reed@android.com8a1c16f2008-12-17 15:59:43 +00001233void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001234 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001235 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001236 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001237 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001238 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239}
1240
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241void SkCanvas::resetMatrix() {
1242 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001243
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244 matrix.reset();
1245 this->setMatrix(matrix);
1246}
1247
1248//////////////////////////////////////////////////////////////////////////////
1249
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001250void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001251 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001252 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1253 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001254}
1255
1256void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001257#ifdef SK_ENABLE_CLIP_QUICKREJECT
1258 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001259 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001260 return false;
1261 }
1262
reed@google.com3b3e8952012-08-16 20:53:31 +00001263 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001264 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001265 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001266
1267 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001268 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001269 }
1270 }
1271#endif
1272
reed@google.com5c3d1472011-02-22 19:12:23 +00001273 AutoValidateClip avc(this);
1274
reed@android.com8a1c16f2008-12-17 15:59:43 +00001275 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001276 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001277 if (!fAllowSoftClip) {
1278 edgeStyle = kHard_ClipEdgeStyle;
1279 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001280
reed1f836ee2014-07-07 07:49:34 -07001281 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001282 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001283 // the matrix. This means we don't have to a) make a path, and b) tell
1284 // the region code to scan-convert the path, only to discover that it
1285 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001286 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001287
reed1f836ee2014-07-07 07:49:34 -07001288 fMCRec->fMatrix.mapRect(&r, rect);
joshualittde358a92015-02-05 08:19:35 -08001289 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001290 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001292 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001293 // and clip against that, since it can handle any matrix. However, to
1294 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1295 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001296 SkPath path;
1297
1298 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001299 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300 }
1301}
1302
reed73e714e2014-09-04 09:02:23 -07001303static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1304 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001305 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001306}
1307
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001308void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001309 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001310 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001311 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001312 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1313 } else {
1314 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001315 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001316}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001317
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001318void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001319 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001320 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001321 AutoValidateClip avc(this);
1322
1323 fDeviceCMDirty = true;
1324 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001325 if (!fAllowSoftClip) {
1326 edgeStyle = kHard_ClipEdgeStyle;
1327 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001328
joshualittde358a92015-02-05 08:19:35 -08001329 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001330
1331 SkPath devPath;
1332 devPath.addRRect(transformedRRect);
1333
reed73e714e2014-09-04 09:02:23 -07001334 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001335 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001336 }
1337
1338 SkPath path;
1339 path.addRRect(rrect);
1340 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001341 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001342}
1343
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001344void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001345 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001346 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1347 SkRect r;
1348 if (!path.isInverseFillType() && path.isRect(&r)) {
1349 this->onClipRect(r, op, edgeStyle);
1350 } else {
1351 this->onClipPath(path, op, edgeStyle);
1352 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001353}
1354
1355void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001356#ifdef SK_ENABLE_CLIP_QUICKREJECT
1357 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001358 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001359 return false;
1360 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001361
reed@google.com3b3e8952012-08-16 20:53:31 +00001362 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001363 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001364 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001365
reed@google.comda17f752012-08-16 18:27:05 +00001366 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001367 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001368 }
1369 }
1370#endif
1371
reed@google.com5c3d1472011-02-22 19:12:23 +00001372 AutoValidateClip avc(this);
1373
reed@android.com8a1c16f2008-12-17 15:59:43 +00001374 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001375 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001376 if (!fAllowSoftClip) {
1377 edgeStyle = kHard_ClipEdgeStyle;
1378 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001379
1380 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001381 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001382
reed@google.comfe701122011-11-08 19:41:23 +00001383 // Check if the transfomation, or the original path itself
1384 // made us empty. Note this can also happen if we contained NaN
1385 // values. computing the bounds detects this, and will set our
1386 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1387 if (devPath.getBounds().isEmpty()) {
1388 // resetting the path will remove any NaN or other wanky values
1389 // that might upset our scan converter.
1390 devPath.reset();
1391 }
1392
reed@google.com5c3d1472011-02-22 19:12:23 +00001393 // if we called path.swap() we could avoid a deep copy of this path
joshualittde358a92015-02-05 08:19:35 -08001394 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001395
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001396 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001397 bool clipIsAA = getClipStack()->asPath(&devPath);
1398 if (clipIsAA) {
1399 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001400 }
fmalita1a481fe2015-02-04 07:39:34 -08001401
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001402 op = SkRegion::kReplace_Op;
1403 }
1404
reed73e714e2014-09-04 09:02:23 -07001405 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001406}
1407
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001408void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001409 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001410 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001411}
1412
1413void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001414 AutoValidateClip avc(this);
1415
reed@android.com8a1c16f2008-12-17 15:59:43 +00001416 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001417 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418
reed@google.com5c3d1472011-02-22 19:12:23 +00001419 // todo: signal fClipStack that we have a region, and therefore (I guess)
1420 // we have to ignore it, and use the region directly?
joshualittde358a92015-02-05 08:19:35 -08001421 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001422
reed1f836ee2014-07-07 07:49:34 -07001423 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424}
1425
reed@google.com819c9212011-02-23 18:56:55 +00001426#ifdef SK_DEBUG
1427void SkCanvas::validateClip() const {
1428 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001429 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001430 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001431 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001432 return;
1433 }
1434
reed@google.com819c9212011-02-23 18:56:55 +00001435 SkIRect ir;
1436 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001437 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001438
joshualittde358a92015-02-05 08:19:35 -08001439 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001440 const SkClipStack::Element* element;
1441 while ((element = iter.next()) != NULL) {
1442 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001443 case SkClipStack::Element::kRect_Type:
1444 element->getRect().round(&ir);
1445 tmpClip.op(ir, element->getOp());
1446 break;
1447 case SkClipStack::Element::kEmpty_Type:
1448 tmpClip.setEmpty();
1449 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001450 default: {
1451 SkPath path;
1452 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001453 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001454 break;
1455 }
reed@google.com819c9212011-02-23 18:56:55 +00001456 }
1457 }
reed@google.com819c9212011-02-23 18:56:55 +00001458}
1459#endif
1460
reed@google.com90c07ea2012-04-13 13:50:27 +00001461void SkCanvas::replayClips(ClipVisitor* visitor) const {
joshualittde358a92015-02-05 08:19:35 -08001462 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001463 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001464
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001465 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001466 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001467 }
1468}
1469
reed@google.com5c3d1472011-02-22 19:12:23 +00001470///////////////////////////////////////////////////////////////////////////////
1471
reed@google.com754de5f2014-02-24 19:38:20 +00001472bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001473 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001474}
1475
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001476bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001477 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001478}
1479
reed@google.com3b3e8952012-08-16 20:53:31 +00001480bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001481 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001482 return true;
1483
reed1f836ee2014-07-07 07:49:34 -07001484 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001485 return true;
1486 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001487
reed1f836ee2014-07-07 07:49:34 -07001488 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001489 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001490 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001491 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001492 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001493 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001494
reed@android.coma380ae42009-07-21 01:17:02 +00001495 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001496 // TODO: should we use | instead, or compare all 4 at once?
1497 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001498 return true;
1499 }
reed@google.comc0784db2013-12-13 21:16:12 +00001500 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001501 return true;
1502 }
1503 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001504 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001505}
1506
reed@google.com3b3e8952012-08-16 20:53:31 +00001507bool SkCanvas::quickReject(const SkPath& path) const {
1508 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001509}
1510
reed@google.com3b3e8952012-08-16 20:53:31 +00001511bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001512 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001513 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001514 return false;
1515 }
1516
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001517 SkMatrix inverse;
1518 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001519 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001520 if (bounds) {
1521 bounds->setEmpty();
1522 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001523 return false;
1524 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001525
bsalomon49f085d2014-09-05 13:34:00 -07001526 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001527 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001528 // adjust it outwards in case we are antialiasing
1529 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001530
reed@google.com8f4d2302013-12-17 16:44:46 +00001531 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1532 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001533 inverse.mapRect(bounds, r);
1534 }
1535 return true;
1536}
1537
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001538bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001539 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001540 if (clip.isEmpty()) {
1541 if (bounds) {
1542 bounds->setEmpty();
1543 }
1544 return false;
1545 }
1546
bsalomon49f085d2014-09-05 13:34:00 -07001547 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001548 *bounds = clip.getBounds();
1549 }
1550 return true;
1551}
1552
reed@android.com8a1c16f2008-12-17 15:59:43 +00001553const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001554 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001555}
1556
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001557const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001558 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001559}
1560
reed@google.com9c135db2014-03-12 18:28:35 +00001561GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1562 SkBaseDevice* dev = this->getTopDevice();
1563 return dev ? dev->accessRenderTarget() : NULL;
1564}
1565
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001566GrContext* SkCanvas::getGrContext() {
1567#if SK_SUPPORT_GPU
1568 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001569 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001570 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001571 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001572 return renderTarget->getContext();
1573 }
1574 }
1575#endif
1576
1577 return NULL;
1578
1579}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001580
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001581void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1582 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001583 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001584 if (outer.isEmpty()) {
1585 return;
1586 }
1587 if (inner.isEmpty()) {
1588 this->drawRRect(outer, paint);
1589 return;
1590 }
1591
1592 // We don't have this method (yet), but technically this is what we should
1593 // be able to assert...
1594 // SkASSERT(outer.contains(inner));
1595 //
1596 // For now at least check for containment of bounds
1597 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1598
1599 this->onDrawDRRect(outer, inner, paint);
1600}
1601
reed41af9662015-01-05 07:49:08 -08001602// These need to stop being virtual -- clients need to override the onDraw... versions
1603
1604void SkCanvas::drawPaint(const SkPaint& paint) {
1605 this->onDrawPaint(paint);
1606}
1607
1608void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1609 this->onDrawRect(r, paint);
1610}
1611
1612void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1613 this->onDrawOval(r, paint);
1614}
1615
1616void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1617 this->onDrawRRect(rrect, paint);
1618}
1619
1620void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1621 this->onDrawPoints(mode, count, pts, paint);
1622}
1623
1624void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1625 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1626 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1627 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1628 indices, indexCount, paint);
1629}
1630
1631void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1632 this->onDrawPath(path, paint);
1633}
1634
1635void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1636 this->onDrawImage(image, dx, dy, paint);
1637}
1638
1639void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1640 const SkPaint* paint) {
1641 this->onDrawImageRect(image, src, dst, paint);
1642}
1643
1644void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1645 this->onDrawBitmap(bitmap, dx, dy, paint);
1646}
1647
1648void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1649 const SkPaint* paint, DrawBitmapRectFlags flags) {
1650 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1651}
1652
1653void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1654 const SkPaint* paint) {
1655 this->onDrawBitmapNine(bitmap, center, dst, paint);
1656}
1657
1658void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
1659 this->onDrawSprite(bitmap, left, top, paint);
1660}
1661
reed@android.com8a1c16f2008-12-17 15:59:43 +00001662//////////////////////////////////////////////////////////////////////////////
1663// These are the virtual drawing methods
1664//////////////////////////////////////////////////////////////////////////////
1665
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001666void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001667 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001668 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1669 }
1670}
1671
reed41af9662015-01-05 07:49:08 -08001672void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001673 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001674 this->internalDrawPaint(paint);
1675}
1676
1677void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001678 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001679
1680 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001681 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001682 }
1683
reed@google.com4e2b3d32011-04-07 14:18:59 +00001684 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001685}
1686
reed41af9662015-01-05 07:49:08 -08001687void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1688 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001689 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001690 if ((long)count <= 0) {
1691 return;
1692 }
1693
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001694 SkRect r, storage;
1695 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001696 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001697 // special-case 2 points (common for drawing a single line)
1698 if (2 == count) {
1699 r.set(pts[0], pts[1]);
1700 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001701 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001702 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001703 bounds = &paint.computeFastStrokeBounds(r, &storage);
1704 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001705 return;
1706 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001707 }
reed@google.coma584aed2012-05-16 14:06:02 +00001708
reed@android.com8a1c16f2008-12-17 15:59:43 +00001709 SkASSERT(pts != NULL);
1710
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001711 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001712
reed@android.com8a1c16f2008-12-17 15:59:43 +00001713 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001714 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001715 }
reed@google.com4b226022011-01-11 18:32:13 +00001716
reed@google.com4e2b3d32011-04-07 14:18:59 +00001717 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001718}
1719
reed41af9662015-01-05 07:49:08 -08001720void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001721 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001722 SkRect storage;
1723 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001724 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001725 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1726 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1727 SkRect tmp(r);
1728 tmp.sort();
1729
1730 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001731 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001732 return;
1733 }
1734 }
reed@google.com4b226022011-01-11 18:32:13 +00001735
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001736 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001737
1738 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001739 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001740 }
1741
reed@google.com4e2b3d32011-04-07 14:18:59 +00001742 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001743}
1744
reed41af9662015-01-05 07:49:08 -08001745void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001746 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001747 SkRect storage;
1748 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001749 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001750 bounds = &paint.computeFastBounds(oval, &storage);
1751 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001752 return;
1753 }
1754 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001755
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001756 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001757
1758 while (iter.next()) {
1759 iter.fDevice->drawOval(iter, oval, looper.paint());
1760 }
1761
1762 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001763}
1764
reed41af9662015-01-05 07:49:08 -08001765void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001766 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001767 SkRect storage;
1768 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001769 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001770 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1771 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001772 return;
1773 }
1774 }
1775
1776 if (rrect.isRect()) {
1777 // call the non-virtual version
1778 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001779 return;
1780 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001781 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001782 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1783 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001784 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001785
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001786 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001787
1788 while (iter.next()) {
1789 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1790 }
1791
1792 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001793}
1794
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001795void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1796 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001797 SkRect storage;
1798 const SkRect* bounds = NULL;
1799 if (paint.canComputeFastBounds()) {
1800 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1801 if (this->quickReject(*bounds)) {
1802 return;
1803 }
1804 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001805
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001806 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001807
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001808 while (iter.next()) {
1809 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1810 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001811
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001812 LOOPER_END
1813}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001814
reed41af9662015-01-05 07:49:08 -08001815void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001816 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001817 if (!path.isFinite()) {
1818 return;
1819 }
1820
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001821 SkRect storage;
1822 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001823 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001824 const SkRect& pathBounds = path.getBounds();
1825 bounds = &paint.computeFastBounds(pathBounds, &storage);
1826 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001827 return;
1828 }
1829 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001830
1831 const SkRect& r = path.getBounds();
1832 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001833 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001834 this->internalDrawPaint(paint);
1835 }
1836 return;
1837 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001838
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001839 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001840
1841 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001842 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001843 }
1844
reed@google.com4e2b3d32011-04-07 14:18:59 +00001845 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001846}
1847
kkinnunena9baa652015-03-05 06:33:54 -08001848void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001849 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
kkinnunena9baa652015-03-05 06:33:54 -08001850 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001851}
1852
reed41af9662015-01-05 07:49:08 -08001853void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1854 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001855 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
kkinnunena9baa652015-03-05 06:33:54 -08001856 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001857}
1858
reed41af9662015-01-05 07:49:08 -08001859void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001860 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001861 SkDEBUGCODE(bitmap.validate();)
1862
reed@google.com3d608122011-11-21 15:16:16 +00001863 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001864 SkRect bounds = {
1865 x, y,
1866 x + SkIntToScalar(bitmap.width()),
1867 y + SkIntToScalar(bitmap.height())
1868 };
1869 if (paint) {
1870 (void)paint->computeFastBounds(bounds, &bounds);
1871 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001872 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001873 return;
1874 }
1875 }
reed@google.com4b226022011-01-11 18:32:13 +00001876
reed@android.com8a1c16f2008-12-17 15:59:43 +00001877 SkMatrix matrix;
1878 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001879 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001880}
1881
reed@google.com9987ec32011-09-07 11:57:52 +00001882// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00001883void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001884 const SkRect& dst, const SkPaint* paint,
1885 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001886 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001887 return;
1888 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001889
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001890 SkRect storage;
1891 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00001892 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001893 if (paint) {
1894 bounds = &paint->computeFastBounds(dst, &storage);
1895 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001896 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001897 return;
1898 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001899 }
reed@google.com3d608122011-11-21 15:16:16 +00001900
reed@google.com33535f32012-09-25 15:37:50 +00001901 SkLazyPaint lazy;
1902 if (NULL == paint) {
1903 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001904 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001905
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001906 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001907
reed@google.com33535f32012-09-25 15:37:50 +00001908 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001909 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00001910 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001911
reed@google.com33535f32012-09-25 15:37:50 +00001912 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001913}
1914
reed41af9662015-01-05 07:49:08 -08001915void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1916 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08001917 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00001918 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001919 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00001920}
1921
reed@google.com9987ec32011-09-07 11:57:52 +00001922void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1923 const SkIRect& center, const SkRect& dst,
1924 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001925 if (bitmap.drawsNothing()) {
1926 return;
1927 }
reed@google.com3d608122011-11-21 15:16:16 +00001928 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00001929 SkRect storage;
1930 const SkRect* bounds = &dst;
1931 if (paint) {
1932 bounds = &paint->computeFastBounds(dst, &storage);
1933 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001934 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001935 return;
1936 }
1937 }
1938
reed@google.com9987ec32011-09-07 11:57:52 +00001939 const int32_t w = bitmap.width();
1940 const int32_t h = bitmap.height();
1941
1942 SkIRect c = center;
1943 // pin center to the bounds of the bitmap
1944 c.fLeft = SkMax32(0, center.fLeft);
1945 c.fTop = SkMax32(0, center.fTop);
1946 c.fRight = SkPin32(center.fRight, c.fLeft, w);
1947 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1948
reed@google.com71121732012-09-18 15:14:33 +00001949 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001950 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00001951 };
1952 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001953 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00001954 };
reed@google.com9987ec32011-09-07 11:57:52 +00001955 SkScalar dstX[4] = {
1956 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
1957 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
1958 };
1959 SkScalar dstY[4] = {
1960 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
1961 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
1962 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001963
reed@google.com9987ec32011-09-07 11:57:52 +00001964 if (dstX[1] > dstX[2]) {
1965 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
1966 dstX[2] = dstX[1];
1967 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001968
reed@google.com9987ec32011-09-07 11:57:52 +00001969 if (dstY[1] > dstY[2]) {
1970 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
1971 dstY[2] = dstY[1];
1972 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001973
reed@google.com9987ec32011-09-07 11:57:52 +00001974 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00001975 SkRect s, d;
1976
reed@google.com9987ec32011-09-07 11:57:52 +00001977 s.fTop = srcY[y];
1978 s.fBottom = srcY[y+1];
1979 d.fTop = dstY[y];
1980 d.fBottom = dstY[y+1];
1981 for (int x = 0; x < 3; x++) {
1982 s.fLeft = srcX[x];
1983 s.fRight = srcX[x+1];
1984 d.fLeft = dstX[x];
1985 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001986 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00001987 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00001988 }
1989 }
1990}
1991
reed41af9662015-01-05 07:49:08 -08001992void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1993 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001994 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00001995 SkDEBUGCODE(bitmap.validate();)
1996
1997 // Need a device entry-point, so gpu can use a mesh
1998 this->internalDrawBitmapNine(bitmap, center, dst, paint);
1999}
2000
reed@google.comf67e4cf2011-03-15 20:56:58 +00002001class SkDeviceFilteredPaint {
2002public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002003 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002004 uint32_t filteredFlags = device->filterTextFlags(paint);
2005 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002006 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002007 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002008 fPaint = newPaint;
2009 } else {
2010 fPaint = &paint;
2011 }
2012 }
2013
reed@google.comf67e4cf2011-03-15 20:56:58 +00002014 const SkPaint& paint() const { return *fPaint; }
2015
2016private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002017 const SkPaint* fPaint;
2018 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002019};
2020
bungeman@google.com52c748b2011-08-22 21:30:43 +00002021void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2022 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002023 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002024 draw.fDevice->drawRect(draw, r, paint);
2025 } else {
2026 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002027 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002028 draw.fDevice->drawRect(draw, r, p);
2029 }
2030}
2031
2032void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2033 const char text[], size_t byteLength,
2034 SkScalar x, SkScalar y) {
2035 SkASSERT(byteLength == 0 || text != NULL);
2036
2037 // nothing to draw
2038 if (text == NULL || byteLength == 0 ||
2039 draw.fClip->isEmpty() ||
2040 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2041 return;
2042 }
2043
2044 SkScalar width = 0;
2045 SkPoint start;
2046
2047 start.set(0, 0); // to avoid warning
2048 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2049 SkPaint::kStrikeThruText_Flag)) {
2050 width = paint.measureText(text, byteLength);
2051
2052 SkScalar offsetX = 0;
2053 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2054 offsetX = SkScalarHalf(width);
2055 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2056 offsetX = width;
2057 }
2058 start.set(x - offsetX, y);
2059 }
2060
2061 if (0 == width) {
2062 return;
2063 }
2064
2065 uint32_t flags = paint.getFlags();
2066
2067 if (flags & (SkPaint::kUnderlineText_Flag |
2068 SkPaint::kStrikeThruText_Flag)) {
2069 SkScalar textSize = paint.getTextSize();
2070 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2071 SkRect r;
2072
2073 r.fLeft = start.fX;
2074 r.fRight = start.fX + width;
2075
2076 if (flags & SkPaint::kUnderlineText_Flag) {
2077 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2078 start.fY);
2079 r.fTop = offset;
2080 r.fBottom = offset + height;
2081 DrawRect(draw, paint, r, textSize);
2082 }
2083 if (flags & SkPaint::kStrikeThruText_Flag) {
2084 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2085 start.fY);
2086 r.fTop = offset;
2087 r.fBottom = offset + height;
2088 DrawRect(draw, paint, r, textSize);
2089 }
2090 }
2091}
2092
reed@google.come0d9ce82014-04-23 04:00:17 +00002093void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2094 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002095 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002096
2097 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002098 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002099 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002100 DrawTextDecorations(iter, dfp.paint(),
2101 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002102 }
2103
reed@google.com4e2b3d32011-04-07 14:18:59 +00002104 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002105}
2106
reed@google.come0d9ce82014-04-23 04:00:17 +00002107void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2108 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002109 SkPoint textOffset = SkPoint::Make(0, 0);
2110
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002111 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002112
reed@android.com8a1c16f2008-12-17 15:59:43 +00002113 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002114 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002115 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002116 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002117 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002118
reed@google.com4e2b3d32011-04-07 14:18:59 +00002119 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002120}
2121
reed@google.come0d9ce82014-04-23 04:00:17 +00002122void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2123 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002124
2125 SkPoint textOffset = SkPoint::Make(0, constY);
2126
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002127 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002128
reed@android.com8a1c16f2008-12-17 15:59:43 +00002129 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002130 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002131 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002132 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002133 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002134
reed@google.com4e2b3d32011-04-07 14:18:59 +00002135 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002136}
2137
reed@google.come0d9ce82014-04-23 04:00:17 +00002138void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2139 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002140 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002141
reed@android.com8a1c16f2008-12-17 15:59:43 +00002142 while (iter.next()) {
2143 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002144 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002145 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002146
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002147 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002148}
2149
fmalita00d5c2c2014-08-21 08:53:26 -07002150void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2151 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002152
fmalita85d5eb92015-03-04 11:20:12 -08002153 SkRect storage;
2154 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002155 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002156 storage = blob->bounds().makeOffset(x, y);
2157 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002158
fmalita85d5eb92015-03-04 11:20:12 -08002159 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002160 return;
2161 }
2162 }
2163
fmalita024f9962015-03-03 19:08:17 -08002164 // We cannot filter in the looper as we normally do, because the paint is
2165 // incomplete at this point (text-related attributes are embedded within blob run paints).
2166 SkDrawFilter* drawFilter = fMCRec->fFilter;
2167 fMCRec->fFilter = NULL;
2168
fmalita85d5eb92015-03-04 11:20:12 -08002169 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002170
fmalitaaa1b9122014-08-28 14:32:24 -07002171 while (iter.next()) {
2172 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002173 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002174 }
2175
fmalitaaa1b9122014-08-28 14:32:24 -07002176 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002177
2178 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002179}
2180
reed@google.come0d9ce82014-04-23 04:00:17 +00002181// These will become non-virtual, so they always call the (virtual) onDraw... method
2182void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2183 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002184 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002185 this->onDrawText(text, byteLength, x, y, paint);
2186}
2187void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2188 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002189 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002190 this->onDrawPosText(text, byteLength, pos, paint);
2191}
2192void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2193 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002194 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002195 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2196}
2197void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2198 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002199 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002200 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2201}
fmalita00d5c2c2014-08-21 08:53:26 -07002202void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2203 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002204 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002205 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002206 this->onDrawTextBlob(blob, x, y, paint);
2207 }
2208}
reed@google.come0d9ce82014-04-23 04:00:17 +00002209
reed41af9662015-01-05 07:49:08 -08002210void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2211 const SkPoint verts[], const SkPoint texs[],
2212 const SkColor colors[], SkXfermode* xmode,
2213 const uint16_t indices[], int indexCount,
2214 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002215 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002216 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002217
reed@android.com8a1c16f2008-12-17 15:59:43 +00002218 while (iter.next()) {
2219 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002220 colors, xmode, indices, indexCount,
2221 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002222 }
reed@google.com4b226022011-01-11 18:32:13 +00002223
reed@google.com4e2b3d32011-04-07 14:18:59 +00002224 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002225}
2226
dandovb3c9d1c2014-08-12 08:34:29 -07002227void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2228 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002229 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002230 if (NULL == cubics) {
2231 return;
2232 }
mtklein6cfa73a2014-08-13 13:33:49 -07002233
dandovecfff212014-08-04 10:02:00 -07002234 // Since a patch is always within the convex hull of the control points, we discard it when its
2235 // bounding rectangle is completely outside the current clip.
2236 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002237 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002238 if (this->quickReject(bounds)) {
2239 return;
2240 }
mtklein6cfa73a2014-08-13 13:33:49 -07002241
dandovb3c9d1c2014-08-12 08:34:29 -07002242 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2243}
2244
2245void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2246 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2247
dandovecfff212014-08-04 10:02:00 -07002248 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002249
dandovecfff212014-08-04 10:02:00 -07002250 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002251 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002252 }
mtklein6cfa73a2014-08-13 13:33:49 -07002253
dandovecfff212014-08-04 10:02:00 -07002254 LOOPER_END
2255}
2256
reed3cb38402015-02-06 08:36:15 -08002257void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002258 if (dr && !this->quickReject(dr->getBounds())) {
2259 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002260 }
2261}
2262
reed3cb38402015-02-06 08:36:15 -08002263void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002264 dr->draw(this);
2265}
2266
reed@android.com8a1c16f2008-12-17 15:59:43 +00002267//////////////////////////////////////////////////////////////////////////////
2268// These methods are NOT virtual, and therefore must call back into virtual
2269// methods, rather than actually drawing themselves.
2270//////////////////////////////////////////////////////////////////////////////
2271
2272void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002273 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002274 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002275 SkPaint paint;
2276
2277 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002278 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002279 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002280 }
2281 this->drawPaint(paint);
2282}
2283
reed@android.com845fdac2009-06-23 03:01:32 +00002284void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002285 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002286 SkPaint paint;
2287
2288 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002289 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002290 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002291 }
2292 this->drawPaint(paint);
2293}
2294
2295void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002296 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002297 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002298
reed@android.com8a1c16f2008-12-17 15:59:43 +00002299 pt.set(x, y);
2300 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2301}
2302
2303void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002304 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305 SkPoint pt;
2306 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002307
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308 pt.set(x, y);
2309 paint.setColor(color);
2310 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2311}
2312
2313void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2314 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002315 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002316 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002317
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318 pts[0].set(x0, y0);
2319 pts[1].set(x1, y1);
2320 this->drawPoints(kLines_PointMode, 2, pts, paint);
2321}
2322
2323void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2324 SkScalar right, SkScalar bottom,
2325 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002326 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002327 SkRect r;
2328
2329 r.set(left, top, right, bottom);
2330 this->drawRect(r, paint);
2331}
2332
2333void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2334 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002335 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002336 if (radius < 0) {
2337 radius = 0;
2338 }
2339
2340 SkRect r;
2341 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002342 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002343}
2344
2345void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2346 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002347 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002348 if (rx > 0 && ry > 0) {
2349 if (paint.canComputeFastBounds()) {
2350 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002351 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002352 return;
2353 }
2354 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002355 SkRRect rrect;
2356 rrect.setRectXY(r, rx, ry);
2357 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002358 } else {
2359 this->drawRect(r, paint);
2360 }
2361}
2362
reed@android.com8a1c16f2008-12-17 15:59:43 +00002363void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2364 SkScalar sweepAngle, bool useCenter,
2365 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002366 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002367 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2368 this->drawOval(oval, paint);
2369 } else {
2370 SkPath path;
2371 if (useCenter) {
2372 path.moveTo(oval.centerX(), oval.centerY());
2373 }
2374 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2375 if (useCenter) {
2376 path.close();
2377 }
2378 this->drawPath(path, paint);
2379 }
2380}
2381
2382void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2383 const SkPath& path, SkScalar hOffset,
2384 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002385 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002386 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002387
reed@android.com8a1c16f2008-12-17 15:59:43 +00002388 matrix.setTranslate(hOffset, vOffset);
2389 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2390}
2391
reed@android.comf76bacf2009-05-13 14:00:33 +00002392///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002393void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002394 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002395 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002396 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002397 }
2398}
2399
reedd5fa1a42014-08-09 11:08:05 -07002400void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002401 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002402 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002403 if (matrix && matrix->isIdentity()) {
2404 matrix = NULL;
2405 }
2406 this->onDrawPicture(picture, matrix, paint);
2407 }
2408}
robertphillips9b14f262014-06-04 05:40:44 -07002409
reedd5fa1a42014-08-09 11:08:05 -07002410void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2411 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002412 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002413 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002414 // Canvas has to first give the device the opportunity to render
2415 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002416 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002417 return; // the device has rendered the entire picture
2418 }
2419 }
2420
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002421 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002422
robertphillipsc5ba71d2014-09-04 08:42:50 -07002423 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002424}
2425
reed@android.com8a1c16f2008-12-17 15:59:43 +00002426///////////////////////////////////////////////////////////////////////////////
2427///////////////////////////////////////////////////////////////////////////////
2428
2429SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002430 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002431
2432 SkASSERT(canvas);
2433
2434 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2435 fDone = !fImpl->next();
2436}
2437
2438SkCanvas::LayerIter::~LayerIter() {
2439 fImpl->~SkDrawIter();
2440}
2441
2442void SkCanvas::LayerIter::next() {
2443 fDone = !fImpl->next();
2444}
2445
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002446SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002447 return fImpl->getDevice();
2448}
2449
2450const SkMatrix& SkCanvas::LayerIter::matrix() const {
2451 return fImpl->getMatrix();
2452}
2453
2454const SkPaint& SkCanvas::LayerIter::paint() const {
2455 const SkPaint* paint = fImpl->getPaint();
2456 if (NULL == paint) {
2457 paint = &fDefaultPaint;
2458 }
2459 return *paint;
2460}
2461
2462const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2463int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2464int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002465
2466///////////////////////////////////////////////////////////////////////////////
2467
fmalitac3b589a2014-06-05 12:40:07 -07002468SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002469
2470///////////////////////////////////////////////////////////////////////////////
2471
2472static bool supported_for_raster_canvas(const SkImageInfo& info) {
2473 switch (info.alphaType()) {
2474 case kPremul_SkAlphaType:
2475 case kOpaque_SkAlphaType:
2476 break;
2477 default:
2478 return false;
2479 }
2480
2481 switch (info.colorType()) {
2482 case kAlpha_8_SkColorType:
2483 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002484 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002485 break;
2486 default:
2487 return false;
2488 }
2489
2490 return true;
2491}
2492
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002493SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2494 if (!supported_for_raster_canvas(info)) {
2495 return NULL;
2496 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002497
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002498 SkBitmap bitmap;
2499 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2500 return NULL;
2501 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002502 return SkNEW_ARGS(SkCanvas, (bitmap));
2503}
reedd5fa1a42014-08-09 11:08:05 -07002504
2505///////////////////////////////////////////////////////////////////////////////
2506
2507SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002508 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002509 : fCanvas(canvas)
2510 , fSaveCount(canvas->getSaveCount())
2511{
bsalomon49f085d2014-09-05 13:34:00 -07002512 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002513 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002514 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002515 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002516 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002517 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002518 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002519 canvas->save();
2520 }
mtklein6cfa73a2014-08-13 13:33:49 -07002521
bsalomon49f085d2014-09-05 13:34:00 -07002522 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002523 canvas->concat(*matrix);
2524 }
2525}
2526
2527SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2528 fCanvas->restoreToCount(fSaveCount);
2529}