blob: a31ded05864a9b436532e6320f09e8efc413cd7d [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,
302 true, 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);
798 fSaveCount -= 1;
799 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);
reed2ff1fce2014-12-11 07:07:37 -0800882 fSaveCount += 1;
883 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy);
884 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);
reed2ff1fce2014-12-11 07:07:37 -0800892 fSaveCount += 1;
893 this->internalSaveLayer(bounds, paint, flags, false, strategy);
894 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,
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000898 bool justForImageFilter, 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
reed@google.comb55deeb2012-01-06 14:43:09 +0000920 // Kill the imagefilter if our device doesn't allow it
921 SkLazyPaint lazyP;
922 if (paint && paint->getImageFilter()) {
923 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
reed@google.com8926b162012-03-23 15:36:36 +0000924 if (justForImageFilter) {
925 // early exit if the layer was just for the imageFilter
reed2ff1fce2014-12-11 07:07:37 -0800926 return;
reed@google.com8926b162012-03-23 15:36:36 +0000927 }
reed@google.comb55deeb2012-01-06 14:43:09 +0000928 SkPaint* p = lazyP.set(*paint);
929 p->setImageFilter(NULL);
930 paint = p;
931 }
932 }
933
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000934 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
935 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
936 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000937
reedb2db8982014-11-13 12:41:02 -0800938 SkBaseDevice* device = this->getTopDevice();
939 if (NULL == device) {
940 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800941 return;
reed@google.com76dd2772012-01-05 21:15:07 +0000942 }
reedb2db8982014-11-13 12:41:02 -0800943
944 SkBaseDevice::Usage usage = SkBaseDevice::kSaveLayer_Usage;
945 if (paint && paint->getImageFilter()) {
946 usage = SkBaseDevice::kImageFilter_Usage;
947 }
948 device = device->onCreateCompatibleDevice(SkBaseDevice::CreateInfo(info, usage,
949 fProps.pixelGeometry()));
bungeman@google.come25c6842011-08-17 14:53:54 +0000950 if (NULL == device) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800951 SkErrorInternals::SetError( kInternalError_SkError,
952 "Unable to create device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800953 return;
bungeman@google.come25c6842011-08-17 14:53:54 +0000954 }
bsalomon@google.come97f0852011-06-17 13:10:25 +0000955
reed@google.com6f8f2922011-03-04 22:27:10 +0000956 device->setOrigin(ir.fLeft, ir.fTop);
reed96e657d2015-03-10 17:30:07 -0700957 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000958 device->unref();
959
960 layer->fNext = fMCRec->fTopLayer;
961 fMCRec->fLayer = layer;
962 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000963}
964
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000965int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
966 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
967}
968
reed@android.com8a1c16f2008-12-17 15:59:43 +0000969int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
970 SaveFlags flags) {
971 if (0xFF == alpha) {
972 return this->saveLayer(bounds, NULL, flags);
973 } else {
974 SkPaint tmpPaint;
975 tmpPaint.setAlpha(alpha);
976 return this->saveLayer(bounds, &tmpPaint, flags);
977 }
978}
979
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980void SkCanvas::internalRestore() {
981 SkASSERT(fMCStack.count() != 0);
982
983 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +0000984 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000985
joshualittde358a92015-02-05 08:19:35 -0800986 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +0000987
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000988 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989 DeviceCM* layer = fMCRec->fLayer; // may be null
990 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
991 fMCRec->fLayer = NULL;
992
993 // now do the normal restore()
994 fMCRec->~MCRec(); // balanced in save()
995 fMCStack.pop_back();
996 fMCRec = (MCRec*)fMCStack.back();
997
998 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
999 since if we're being recorded, we don't want to record this (the
1000 recorder will have already recorded the restore).
1001 */
bsalomon49f085d2014-09-05 13:34:00 -07001002 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001003 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001004 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001005 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1006 layer->fPaint);
1007 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001008 fDeviceCMDirty = true;
1009 }
1010 SkDELETE(layer);
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001011 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001012}
1013
reed4a8126e2014-09-22 07:29:03 -07001014SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1015 if (NULL == props) {
1016 props = &fProps;
1017 }
1018 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001019}
1020
reed4a8126e2014-09-22 07:29:03 -07001021SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001022 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001023 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001024}
1025
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001026SkImageInfo SkCanvas::imageInfo() const {
1027 SkBaseDevice* dev = this->getDevice();
1028 if (dev) {
1029 return dev->imageInfo();
1030 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001031 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001032 }
1033}
1034
1035const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1036 return this->onPeekPixels(info, rowBytes);
1037}
1038
1039const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1040 SkBaseDevice* dev = this->getDevice();
1041 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1042}
1043
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001044void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1045 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1046 if (pixels && origin) {
1047 *origin = this->getTopDevice(false)->getOrigin();
1048 }
1049 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001050}
1051
1052void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1053 SkBaseDevice* dev = this->getTopDevice();
1054 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1055}
1056
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001057SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1058 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1059 if (NULL == fAddr) {
1060 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001061 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001062 return; // failure, fAddr is NULL
1063 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001064 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1065 return; // failure, fAddr is NULL
1066 }
1067 fAddr = fBitmap.getPixels();
1068 fRowBytes = fBitmap.rowBytes();
1069 }
1070 SkASSERT(fAddr); // success
1071}
1072
1073bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1074 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001075 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001076 } else {
1077 bitmap->reset();
1078 return false;
1079 }
1080}
1081
reed@android.com8a1c16f2008-12-17 15:59:43 +00001082/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001083void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001084 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001085 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086 return;
1087 }
1088
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001089 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001091 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001092 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001093
1094 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001095
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001096 SkRect storage;
1097 const SkRect* bounds = NULL;
1098 if (paint && paint->canComputeFastBounds()) {
1099 bitmap.getBounds(&storage);
1100 matrix.mapRect(&storage);
1101 bounds = &paint->computeFastBounds(storage, &storage);
1102 }
1103
1104 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001105
1106 while (iter.next()) {
1107 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1108 }
1109
1110 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111}
1112
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001113void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed@google.com8926b162012-03-23 15:36:36 +00001114 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001115 SkPaint tmp;
1116 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001117 paint = &tmp;
1118 }
reed@google.com4b226022011-01-11 18:32:13 +00001119
reed@google.com8926b162012-03-23 15:36:36 +00001120 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001121 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001122 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001123 paint = &looper.paint();
1124 SkImageFilter* filter = paint->getImageFilter();
1125 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001126 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001127 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001128 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001129 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001130 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001131 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001132 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001133 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001134 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001135 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001136 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001137 SkPaint tmpUnfiltered(*paint);
1138 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001139 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1140 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001141 }
1142 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001143 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001144 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001146 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147}
1148
reed41af9662015-01-05 07:49:08 -08001149void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001150 if (gTreatSpriteAsBitmap) {
1151 this->save();
1152 this->resetMatrix();
1153 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1154 this->restore();
1155 return;
1156 }
1157
danakj9881d632014-11-26 12:41:06 -08001158 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001159 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001160 return;
1161 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001162 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001163
reed@google.com8926b162012-03-23 15:36:36 +00001164 SkPaint tmp;
1165 if (NULL == paint) {
1166 paint = &tmp;
1167 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001168
reed@google.com8926b162012-03-23 15:36:36 +00001169 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001170
reed@google.com8926b162012-03-23 15:36:36 +00001171 while (iter.next()) {
1172 paint = &looper.paint();
1173 SkImageFilter* filter = paint->getImageFilter();
1174 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1175 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001176 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001177 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001178 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001179 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001180 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001181 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001182 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001183 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001184 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001185 SkPaint tmpUnfiltered(*paint);
1186 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001187 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001188 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001189 }
1190 } else {
1191 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1192 }
1193 }
1194 LOOPER_END
1195}
1196
reed@android.com8a1c16f2008-12-17 15:59:43 +00001197/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001198void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001199 SkMatrix m;
1200 m.setTranslate(dx, dy);
1201 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001202}
1203
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001204void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001205 SkMatrix m;
1206 m.setScale(sx, sy);
1207 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001208}
1209
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001210void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001211 SkMatrix m;
1212 m.setRotate(degrees);
1213 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001214}
1215
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001216void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001217 SkMatrix m;
1218 m.setSkew(sx, sy);
1219 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001220}
1221
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001222void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001223 if (matrix.isIdentity()) {
1224 return;
1225 }
1226
reed2ff1fce2014-12-11 07:07:37 -08001227 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001229 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001230 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001231
1232 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001233}
1234
reed@android.com8a1c16f2008-12-17 15:59:43 +00001235void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001236 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001237 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001238 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001239 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001240 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241}
1242
reed@android.com8a1c16f2008-12-17 15:59:43 +00001243void SkCanvas::resetMatrix() {
1244 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001245
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246 matrix.reset();
1247 this->setMatrix(matrix);
1248}
1249
1250//////////////////////////////////////////////////////////////////////////////
1251
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001252void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001253 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001254 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1255 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001256}
1257
1258void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001259#ifdef SK_ENABLE_CLIP_QUICKREJECT
1260 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001261 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001262 return false;
1263 }
1264
reed@google.com3b3e8952012-08-16 20:53:31 +00001265 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001266 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001267 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001268
1269 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001270 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001271 }
1272 }
1273#endif
1274
reed@google.com5c3d1472011-02-22 19:12:23 +00001275 AutoValidateClip avc(this);
1276
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001278 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001279 if (!fAllowSoftClip) {
1280 edgeStyle = kHard_ClipEdgeStyle;
1281 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282
reed1f836ee2014-07-07 07:49:34 -07001283 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001284 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001285 // the matrix. This means we don't have to a) make a path, and b) tell
1286 // the region code to scan-convert the path, only to discover that it
1287 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289
reed1f836ee2014-07-07 07:49:34 -07001290 fMCRec->fMatrix.mapRect(&r, rect);
joshualittde358a92015-02-05 08:19:35 -08001291 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001292 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001294 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001295 // and clip against that, since it can handle any matrix. However, to
1296 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1297 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001298 SkPath path;
1299
1300 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001301 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 }
1303}
1304
reed73e714e2014-09-04 09:02:23 -07001305static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1306 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001307 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001308}
1309
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001310void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001311 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001312 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001313 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001314 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1315 } else {
1316 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001317 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001318}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001319
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001320void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001321 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001322 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001323 AutoValidateClip avc(this);
1324
1325 fDeviceCMDirty = true;
1326 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001327 if (!fAllowSoftClip) {
1328 edgeStyle = kHard_ClipEdgeStyle;
1329 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001330
joshualittde358a92015-02-05 08:19:35 -08001331 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001332
1333 SkPath devPath;
1334 devPath.addRRect(transformedRRect);
1335
reed73e714e2014-09-04 09:02:23 -07001336 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001337 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001338 }
1339
1340 SkPath path;
1341 path.addRRect(rrect);
1342 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001343 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001344}
1345
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001346void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001347 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001348 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1349 SkRect r;
1350 if (!path.isInverseFillType() && path.isRect(&r)) {
1351 this->onClipRect(r, op, edgeStyle);
1352 } else {
1353 this->onClipPath(path, op, edgeStyle);
1354 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001355}
1356
1357void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001358#ifdef SK_ENABLE_CLIP_QUICKREJECT
1359 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001360 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001361 return false;
1362 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001363
reed@google.com3b3e8952012-08-16 20:53:31 +00001364 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001365 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001366 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001367
reed@google.comda17f752012-08-16 18:27:05 +00001368 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001369 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001370 }
1371 }
1372#endif
1373
reed@google.com5c3d1472011-02-22 19:12:23 +00001374 AutoValidateClip avc(this);
1375
reed@android.com8a1c16f2008-12-17 15:59:43 +00001376 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001377 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001378 if (!fAllowSoftClip) {
1379 edgeStyle = kHard_ClipEdgeStyle;
1380 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381
1382 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001383 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001384
reed@google.comfe701122011-11-08 19:41:23 +00001385 // Check if the transfomation, or the original path itself
1386 // made us empty. Note this can also happen if we contained NaN
1387 // values. computing the bounds detects this, and will set our
1388 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1389 if (devPath.getBounds().isEmpty()) {
1390 // resetting the path will remove any NaN or other wanky values
1391 // that might upset our scan converter.
1392 devPath.reset();
1393 }
1394
reed@google.com5c3d1472011-02-22 19:12:23 +00001395 // if we called path.swap() we could avoid a deep copy of this path
joshualittde358a92015-02-05 08:19:35 -08001396 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001397
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001398 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001399 bool clipIsAA = getClipStack()->asPath(&devPath);
1400 if (clipIsAA) {
1401 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001402 }
fmalita1a481fe2015-02-04 07:39:34 -08001403
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001404 op = SkRegion::kReplace_Op;
1405 }
1406
reed73e714e2014-09-04 09:02:23 -07001407 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001408}
1409
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001410void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001411 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001412 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001413}
1414
1415void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001416 AutoValidateClip avc(this);
1417
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001419 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420
reed@google.com5c3d1472011-02-22 19:12:23 +00001421 // todo: signal fClipStack that we have a region, and therefore (I guess)
1422 // we have to ignore it, and use the region directly?
joshualittde358a92015-02-05 08:19:35 -08001423 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001424
reed1f836ee2014-07-07 07:49:34 -07001425 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001426}
1427
reed@google.com819c9212011-02-23 18:56:55 +00001428#ifdef SK_DEBUG
1429void SkCanvas::validateClip() const {
1430 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001431 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001432 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001433 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001434 return;
1435 }
1436
reed@google.com819c9212011-02-23 18:56:55 +00001437 SkIRect ir;
1438 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001439 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001440
joshualittde358a92015-02-05 08:19:35 -08001441 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001442 const SkClipStack::Element* element;
1443 while ((element = iter.next()) != NULL) {
1444 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001445 case SkClipStack::Element::kRect_Type:
1446 element->getRect().round(&ir);
1447 tmpClip.op(ir, element->getOp());
1448 break;
1449 case SkClipStack::Element::kEmpty_Type:
1450 tmpClip.setEmpty();
1451 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001452 default: {
1453 SkPath path;
1454 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001455 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001456 break;
1457 }
reed@google.com819c9212011-02-23 18:56:55 +00001458 }
1459 }
reed@google.com819c9212011-02-23 18:56:55 +00001460}
1461#endif
1462
reed@google.com90c07ea2012-04-13 13:50:27 +00001463void SkCanvas::replayClips(ClipVisitor* visitor) const {
joshualittde358a92015-02-05 08:19:35 -08001464 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001465 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001466
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001467 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001468 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001469 }
1470}
1471
reed@google.com5c3d1472011-02-22 19:12:23 +00001472///////////////////////////////////////////////////////////////////////////////
1473
reed@google.com754de5f2014-02-24 19:38:20 +00001474bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001475 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001476}
1477
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001478bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001479 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001480}
1481
reed@google.com3b3e8952012-08-16 20:53:31 +00001482bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001483 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001484 return true;
1485
reed1f836ee2014-07-07 07:49:34 -07001486 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001487 return true;
1488 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001489
reed1f836ee2014-07-07 07:49:34 -07001490 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001491 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001492 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001493 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001494 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001495 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001496
reed@android.coma380ae42009-07-21 01:17:02 +00001497 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001498 // TODO: should we use | instead, or compare all 4 at once?
1499 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001500 return true;
1501 }
reed@google.comc0784db2013-12-13 21:16:12 +00001502 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001503 return true;
1504 }
1505 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001506 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001507}
1508
reed@google.com3b3e8952012-08-16 20:53:31 +00001509bool SkCanvas::quickReject(const SkPath& path) const {
1510 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001511}
1512
reed@google.com3b3e8952012-08-16 20:53:31 +00001513bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001514 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001515 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001516 return false;
1517 }
1518
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001519 SkMatrix inverse;
1520 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001521 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001522 if (bounds) {
1523 bounds->setEmpty();
1524 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001525 return false;
1526 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001527
bsalomon49f085d2014-09-05 13:34:00 -07001528 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001529 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001530 // adjust it outwards in case we are antialiasing
1531 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001532
reed@google.com8f4d2302013-12-17 16:44:46 +00001533 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1534 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001535 inverse.mapRect(bounds, r);
1536 }
1537 return true;
1538}
1539
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001540bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001541 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001542 if (clip.isEmpty()) {
1543 if (bounds) {
1544 bounds->setEmpty();
1545 }
1546 return false;
1547 }
1548
bsalomon49f085d2014-09-05 13:34:00 -07001549 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001550 *bounds = clip.getBounds();
1551 }
1552 return true;
1553}
1554
reed@android.com8a1c16f2008-12-17 15:59:43 +00001555const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001556 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001557}
1558
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001559const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001560 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001561}
1562
reed@google.com9c135db2014-03-12 18:28:35 +00001563GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1564 SkBaseDevice* dev = this->getTopDevice();
1565 return dev ? dev->accessRenderTarget() : NULL;
1566}
1567
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001568GrContext* SkCanvas::getGrContext() {
1569#if SK_SUPPORT_GPU
1570 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001571 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001572 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001573 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001574 return renderTarget->getContext();
1575 }
1576 }
1577#endif
1578
1579 return NULL;
1580
1581}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001582
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001583void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1584 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001585 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001586 if (outer.isEmpty()) {
1587 return;
1588 }
1589 if (inner.isEmpty()) {
1590 this->drawRRect(outer, paint);
1591 return;
1592 }
1593
1594 // We don't have this method (yet), but technically this is what we should
1595 // be able to assert...
1596 // SkASSERT(outer.contains(inner));
1597 //
1598 // For now at least check for containment of bounds
1599 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1600
1601 this->onDrawDRRect(outer, inner, paint);
1602}
1603
reed41af9662015-01-05 07:49:08 -08001604// These need to stop being virtual -- clients need to override the onDraw... versions
1605
1606void SkCanvas::drawPaint(const SkPaint& paint) {
1607 this->onDrawPaint(paint);
1608}
1609
1610void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1611 this->onDrawRect(r, paint);
1612}
1613
1614void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1615 this->onDrawOval(r, paint);
1616}
1617
1618void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1619 this->onDrawRRect(rrect, paint);
1620}
1621
1622void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1623 this->onDrawPoints(mode, count, pts, paint);
1624}
1625
1626void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1627 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1628 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1629 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1630 indices, indexCount, paint);
1631}
1632
1633void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1634 this->onDrawPath(path, paint);
1635}
1636
1637void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1638 this->onDrawImage(image, dx, dy, paint);
1639}
1640
1641void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1642 const SkPaint* paint) {
1643 this->onDrawImageRect(image, src, dst, paint);
1644}
1645
1646void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1647 this->onDrawBitmap(bitmap, dx, dy, paint);
1648}
1649
1650void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1651 const SkPaint* paint, DrawBitmapRectFlags flags) {
1652 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1653}
1654
1655void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1656 const SkPaint* paint) {
1657 this->onDrawBitmapNine(bitmap, center, dst, paint);
1658}
1659
1660void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
1661 this->onDrawSprite(bitmap, left, top, paint);
1662}
1663
reed@android.com8a1c16f2008-12-17 15:59:43 +00001664//////////////////////////////////////////////////////////////////////////////
1665// These are the virtual drawing methods
1666//////////////////////////////////////////////////////////////////////////////
1667
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001668void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001669 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001670 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1671 }
1672}
1673
reed41af9662015-01-05 07:49:08 -08001674void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001675 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001676 this->internalDrawPaint(paint);
1677}
1678
1679void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001680 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681
1682 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001683 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001684 }
1685
reed@google.com4e2b3d32011-04-07 14:18:59 +00001686 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001687}
1688
reed41af9662015-01-05 07:49:08 -08001689void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1690 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001691 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001692 if ((long)count <= 0) {
1693 return;
1694 }
1695
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001696 SkRect r, storage;
1697 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001698 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001699 // special-case 2 points (common for drawing a single line)
1700 if (2 == count) {
1701 r.set(pts[0], pts[1]);
1702 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001703 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001704 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001705 bounds = &paint.computeFastStrokeBounds(r, &storage);
1706 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001707 return;
1708 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001709 }
reed@google.coma584aed2012-05-16 14:06:02 +00001710
reed@android.com8a1c16f2008-12-17 15:59:43 +00001711 SkASSERT(pts != NULL);
1712
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001713 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001714
reed@android.com8a1c16f2008-12-17 15:59:43 +00001715 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001716 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001717 }
reed@google.com4b226022011-01-11 18:32:13 +00001718
reed@google.com4e2b3d32011-04-07 14:18:59 +00001719 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001720}
1721
reed41af9662015-01-05 07:49:08 -08001722void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001723 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001724 SkRect storage;
1725 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001726 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001727 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1728 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1729 SkRect tmp(r);
1730 tmp.sort();
1731
1732 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001733 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001734 return;
1735 }
1736 }
reed@google.com4b226022011-01-11 18:32:13 +00001737
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001738 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001739
1740 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001741 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001742 }
1743
reed@google.com4e2b3d32011-04-07 14:18:59 +00001744 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001745}
1746
reed41af9662015-01-05 07:49:08 -08001747void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001748 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001749 SkRect storage;
1750 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001751 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001752 bounds = &paint.computeFastBounds(oval, &storage);
1753 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001754 return;
1755 }
1756 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001757
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001758 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001759
1760 while (iter.next()) {
1761 iter.fDevice->drawOval(iter, oval, looper.paint());
1762 }
1763
1764 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001765}
1766
reed41af9662015-01-05 07:49:08 -08001767void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001768 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001769 SkRect storage;
1770 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001771 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001772 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1773 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001774 return;
1775 }
1776 }
1777
1778 if (rrect.isRect()) {
1779 // call the non-virtual version
1780 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001781 return;
1782 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001783 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001784 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1785 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001786 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001787
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001788 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001789
1790 while (iter.next()) {
1791 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1792 }
1793
1794 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001795}
1796
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001797void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1798 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001799 SkRect storage;
1800 const SkRect* bounds = NULL;
1801 if (paint.canComputeFastBounds()) {
1802 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1803 if (this->quickReject(*bounds)) {
1804 return;
1805 }
1806 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001807
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001808 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001809
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001810 while (iter.next()) {
1811 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1812 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001813
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001814 LOOPER_END
1815}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001816
reed41af9662015-01-05 07:49:08 -08001817void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001818 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001819 if (!path.isFinite()) {
1820 return;
1821 }
1822
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001823 SkRect storage;
1824 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001825 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001826 const SkRect& pathBounds = path.getBounds();
1827 bounds = &paint.computeFastBounds(pathBounds, &storage);
1828 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001829 return;
1830 }
1831 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001832
1833 const SkRect& r = path.getBounds();
1834 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001835 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001836 this->internalDrawPaint(paint);
1837 }
1838 return;
1839 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001840
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001841 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001842
1843 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001844 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001845 }
1846
reed@google.com4e2b3d32011-04-07 14:18:59 +00001847 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001848}
1849
kkinnunena9baa652015-03-05 06:33:54 -08001850void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001851 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
kkinnunena9baa652015-03-05 06:33:54 -08001852 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001853}
1854
reed41af9662015-01-05 07:49:08 -08001855void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1856 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001857 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
kkinnunena9baa652015-03-05 06:33:54 -08001858 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001859}
1860
reed41af9662015-01-05 07:49:08 -08001861void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001862 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001863 SkDEBUGCODE(bitmap.validate();)
1864
reed@google.com3d608122011-11-21 15:16:16 +00001865 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001866 SkRect bounds = {
1867 x, y,
1868 x + SkIntToScalar(bitmap.width()),
1869 y + SkIntToScalar(bitmap.height())
1870 };
1871 if (paint) {
1872 (void)paint->computeFastBounds(bounds, &bounds);
1873 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001874 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001875 return;
1876 }
1877 }
reed@google.com4b226022011-01-11 18:32:13 +00001878
reed@android.com8a1c16f2008-12-17 15:59:43 +00001879 SkMatrix matrix;
1880 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001881 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001882}
1883
reed@google.com9987ec32011-09-07 11:57:52 +00001884// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00001885void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001886 const SkRect& dst, const SkPaint* paint,
1887 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001888 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001889 return;
1890 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001891
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001892 SkRect storage;
1893 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00001894 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001895 if (paint) {
1896 bounds = &paint->computeFastBounds(dst, &storage);
1897 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001898 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001899 return;
1900 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001901 }
reed@google.com3d608122011-11-21 15:16:16 +00001902
reed@google.com33535f32012-09-25 15:37:50 +00001903 SkLazyPaint lazy;
1904 if (NULL == paint) {
1905 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001906 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001907
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001908 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001909
reed@google.com33535f32012-09-25 15:37:50 +00001910 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001911 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00001912 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001913
reed@google.com33535f32012-09-25 15:37:50 +00001914 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001915}
1916
reed41af9662015-01-05 07:49:08 -08001917void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1918 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08001919 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00001920 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001921 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00001922}
1923
reed@google.com9987ec32011-09-07 11:57:52 +00001924void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1925 const SkIRect& center, const SkRect& dst,
1926 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001927 if (bitmap.drawsNothing()) {
1928 return;
1929 }
reed@google.com3d608122011-11-21 15:16:16 +00001930 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00001931 SkRect storage;
1932 const SkRect* bounds = &dst;
1933 if (paint) {
1934 bounds = &paint->computeFastBounds(dst, &storage);
1935 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001936 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001937 return;
1938 }
1939 }
1940
reed@google.com9987ec32011-09-07 11:57:52 +00001941 const int32_t w = bitmap.width();
1942 const int32_t h = bitmap.height();
1943
1944 SkIRect c = center;
1945 // pin center to the bounds of the bitmap
1946 c.fLeft = SkMax32(0, center.fLeft);
1947 c.fTop = SkMax32(0, center.fTop);
1948 c.fRight = SkPin32(center.fRight, c.fLeft, w);
1949 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1950
reed@google.com71121732012-09-18 15:14:33 +00001951 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001952 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00001953 };
1954 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001955 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00001956 };
reed@google.com9987ec32011-09-07 11:57:52 +00001957 SkScalar dstX[4] = {
1958 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
1959 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
1960 };
1961 SkScalar dstY[4] = {
1962 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
1963 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
1964 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001965
reed@google.com9987ec32011-09-07 11:57:52 +00001966 if (dstX[1] > dstX[2]) {
1967 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
1968 dstX[2] = dstX[1];
1969 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001970
reed@google.com9987ec32011-09-07 11:57:52 +00001971 if (dstY[1] > dstY[2]) {
1972 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
1973 dstY[2] = dstY[1];
1974 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001975
reed@google.com9987ec32011-09-07 11:57:52 +00001976 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00001977 SkRect s, d;
1978
reed@google.com9987ec32011-09-07 11:57:52 +00001979 s.fTop = srcY[y];
1980 s.fBottom = srcY[y+1];
1981 d.fTop = dstY[y];
1982 d.fBottom = dstY[y+1];
1983 for (int x = 0; x < 3; x++) {
1984 s.fLeft = srcX[x];
1985 s.fRight = srcX[x+1];
1986 d.fLeft = dstX[x];
1987 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001988 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00001989 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00001990 }
1991 }
1992}
1993
reed41af9662015-01-05 07:49:08 -08001994void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1995 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001996 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00001997 SkDEBUGCODE(bitmap.validate();)
1998
1999 // Need a device entry-point, so gpu can use a mesh
2000 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2001}
2002
reed@google.comf67e4cf2011-03-15 20:56:58 +00002003class SkDeviceFilteredPaint {
2004public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002005 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002006 uint32_t filteredFlags = device->filterTextFlags(paint);
2007 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002008 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002009 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002010 fPaint = newPaint;
2011 } else {
2012 fPaint = &paint;
2013 }
2014 }
2015
reed@google.comf67e4cf2011-03-15 20:56:58 +00002016 const SkPaint& paint() const { return *fPaint; }
2017
2018private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002019 const SkPaint* fPaint;
2020 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002021};
2022
bungeman@google.com52c748b2011-08-22 21:30:43 +00002023void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2024 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002025 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002026 draw.fDevice->drawRect(draw, r, paint);
2027 } else {
2028 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002029 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002030 draw.fDevice->drawRect(draw, r, p);
2031 }
2032}
2033
2034void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2035 const char text[], size_t byteLength,
2036 SkScalar x, SkScalar y) {
2037 SkASSERT(byteLength == 0 || text != NULL);
2038
2039 // nothing to draw
2040 if (text == NULL || byteLength == 0 ||
2041 draw.fClip->isEmpty() ||
2042 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2043 return;
2044 }
2045
2046 SkScalar width = 0;
2047 SkPoint start;
2048
2049 start.set(0, 0); // to avoid warning
2050 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2051 SkPaint::kStrikeThruText_Flag)) {
2052 width = paint.measureText(text, byteLength);
2053
2054 SkScalar offsetX = 0;
2055 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2056 offsetX = SkScalarHalf(width);
2057 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2058 offsetX = width;
2059 }
2060 start.set(x - offsetX, y);
2061 }
2062
2063 if (0 == width) {
2064 return;
2065 }
2066
2067 uint32_t flags = paint.getFlags();
2068
2069 if (flags & (SkPaint::kUnderlineText_Flag |
2070 SkPaint::kStrikeThruText_Flag)) {
2071 SkScalar textSize = paint.getTextSize();
2072 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2073 SkRect r;
2074
2075 r.fLeft = start.fX;
2076 r.fRight = start.fX + width;
2077
2078 if (flags & SkPaint::kUnderlineText_Flag) {
2079 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2080 start.fY);
2081 r.fTop = offset;
2082 r.fBottom = offset + height;
2083 DrawRect(draw, paint, r, textSize);
2084 }
2085 if (flags & SkPaint::kStrikeThruText_Flag) {
2086 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2087 start.fY);
2088 r.fTop = offset;
2089 r.fBottom = offset + height;
2090 DrawRect(draw, paint, r, textSize);
2091 }
2092 }
2093}
2094
reed@google.come0d9ce82014-04-23 04:00:17 +00002095void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2096 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002097 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002098
2099 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002100 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002101 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002102 DrawTextDecorations(iter, dfp.paint(),
2103 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002104 }
2105
reed@google.com4e2b3d32011-04-07 14:18:59 +00002106 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002107}
2108
reed@google.come0d9ce82014-04-23 04:00:17 +00002109void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2110 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002111 SkPoint textOffset = SkPoint::Make(0, 0);
2112
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002113 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002114
reed@android.com8a1c16f2008-12-17 15:59:43 +00002115 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002116 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002117 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002118 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002119 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002120
reed@google.com4e2b3d32011-04-07 14:18:59 +00002121 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002122}
2123
reed@google.come0d9ce82014-04-23 04:00:17 +00002124void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2125 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002126
2127 SkPoint textOffset = SkPoint::Make(0, constY);
2128
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002129 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002130
reed@android.com8a1c16f2008-12-17 15:59:43 +00002131 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002132 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002133 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002134 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002135 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002136
reed@google.com4e2b3d32011-04-07 14:18:59 +00002137 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002138}
2139
reed@google.come0d9ce82014-04-23 04:00:17 +00002140void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2141 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002142 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002143
reed@android.com8a1c16f2008-12-17 15:59:43 +00002144 while (iter.next()) {
2145 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002146 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002147 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002148
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002149 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002150}
2151
fmalita00d5c2c2014-08-21 08:53:26 -07002152void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2153 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002154
fmalita85d5eb92015-03-04 11:20:12 -08002155 SkRect storage;
2156 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002157 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002158 storage = blob->bounds().makeOffset(x, y);
2159 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002160
fmalita85d5eb92015-03-04 11:20:12 -08002161 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002162 return;
2163 }
2164 }
2165
fmalita024f9962015-03-03 19:08:17 -08002166 // We cannot filter in the looper as we normally do, because the paint is
2167 // incomplete at this point (text-related attributes are embedded within blob run paints).
2168 SkDrawFilter* drawFilter = fMCRec->fFilter;
2169 fMCRec->fFilter = NULL;
2170
fmalita85d5eb92015-03-04 11:20:12 -08002171 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002172
fmalitaaa1b9122014-08-28 14:32:24 -07002173 while (iter.next()) {
2174 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002175 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002176 }
2177
fmalitaaa1b9122014-08-28 14:32:24 -07002178 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002179
2180 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002181}
2182
reed@google.come0d9ce82014-04-23 04:00:17 +00002183// These will become non-virtual, so they always call the (virtual) onDraw... method
2184void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2185 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002186 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002187 this->onDrawText(text, byteLength, x, y, paint);
2188}
2189void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2190 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002191 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002192 this->onDrawPosText(text, byteLength, pos, paint);
2193}
2194void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2195 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002196 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002197 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2198}
2199void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2200 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002201 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002202 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2203}
fmalita00d5c2c2014-08-21 08:53:26 -07002204void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2205 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002206 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002207 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002208 this->onDrawTextBlob(blob, x, y, paint);
2209 }
2210}
reed@google.come0d9ce82014-04-23 04:00:17 +00002211
reed41af9662015-01-05 07:49:08 -08002212void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2213 const SkPoint verts[], const SkPoint texs[],
2214 const SkColor colors[], SkXfermode* xmode,
2215 const uint16_t indices[], int indexCount,
2216 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002217 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002218 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002219
reed@android.com8a1c16f2008-12-17 15:59:43 +00002220 while (iter.next()) {
2221 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002222 colors, xmode, indices, indexCount,
2223 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002224 }
reed@google.com4b226022011-01-11 18:32:13 +00002225
reed@google.com4e2b3d32011-04-07 14:18:59 +00002226 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002227}
2228
dandovb3c9d1c2014-08-12 08:34:29 -07002229void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2230 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002231 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002232 if (NULL == cubics) {
2233 return;
2234 }
mtklein6cfa73a2014-08-13 13:33:49 -07002235
dandovecfff212014-08-04 10:02:00 -07002236 // Since a patch is always within the convex hull of the control points, we discard it when its
2237 // bounding rectangle is completely outside the current clip.
2238 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002239 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002240 if (this->quickReject(bounds)) {
2241 return;
2242 }
mtklein6cfa73a2014-08-13 13:33:49 -07002243
dandovb3c9d1c2014-08-12 08:34:29 -07002244 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2245}
2246
2247void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2248 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2249
dandovecfff212014-08-04 10:02:00 -07002250 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002251
dandovecfff212014-08-04 10:02:00 -07002252 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002253 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002254 }
mtklein6cfa73a2014-08-13 13:33:49 -07002255
dandovecfff212014-08-04 10:02:00 -07002256 LOOPER_END
2257}
2258
reed3cb38402015-02-06 08:36:15 -08002259void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002260 if (dr && !this->quickReject(dr->getBounds())) {
2261 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002262 }
2263}
2264
reed3cb38402015-02-06 08:36:15 -08002265void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002266 dr->draw(this);
2267}
2268
reed@android.com8a1c16f2008-12-17 15:59:43 +00002269//////////////////////////////////////////////////////////////////////////////
2270// These methods are NOT virtual, and therefore must call back into virtual
2271// methods, rather than actually drawing themselves.
2272//////////////////////////////////////////////////////////////////////////////
2273
2274void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002275 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002276 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002277 SkPaint paint;
2278
2279 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002280 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002281 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002282 }
2283 this->drawPaint(paint);
2284}
2285
reed@android.com845fdac2009-06-23 03:01:32 +00002286void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002287 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002288 SkPaint paint;
2289
2290 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002291 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002292 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002293 }
2294 this->drawPaint(paint);
2295}
2296
2297void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002298 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002299 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002300
reed@android.com8a1c16f2008-12-17 15:59:43 +00002301 pt.set(x, y);
2302 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2303}
2304
2305void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002306 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307 SkPoint pt;
2308 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002309
reed@android.com8a1c16f2008-12-17 15:59:43 +00002310 pt.set(x, y);
2311 paint.setColor(color);
2312 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2313}
2314
2315void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2316 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002317 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002319
reed@android.com8a1c16f2008-12-17 15:59:43 +00002320 pts[0].set(x0, y0);
2321 pts[1].set(x1, y1);
2322 this->drawPoints(kLines_PointMode, 2, pts, paint);
2323}
2324
2325void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2326 SkScalar right, SkScalar bottom,
2327 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002328 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002329 SkRect r;
2330
2331 r.set(left, top, right, bottom);
2332 this->drawRect(r, paint);
2333}
2334
2335void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2336 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002337 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002338 if (radius < 0) {
2339 radius = 0;
2340 }
2341
2342 SkRect r;
2343 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002344 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002345}
2346
2347void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2348 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002349 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002350 if (rx > 0 && ry > 0) {
2351 if (paint.canComputeFastBounds()) {
2352 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002353 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002354 return;
2355 }
2356 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002357 SkRRect rrect;
2358 rrect.setRectXY(r, rx, ry);
2359 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002360 } else {
2361 this->drawRect(r, paint);
2362 }
2363}
2364
reed@android.com8a1c16f2008-12-17 15:59:43 +00002365void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2366 SkScalar sweepAngle, bool useCenter,
2367 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002368 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002369 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2370 this->drawOval(oval, paint);
2371 } else {
2372 SkPath path;
2373 if (useCenter) {
2374 path.moveTo(oval.centerX(), oval.centerY());
2375 }
2376 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2377 if (useCenter) {
2378 path.close();
2379 }
2380 this->drawPath(path, paint);
2381 }
2382}
2383
2384void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2385 const SkPath& path, SkScalar hOffset,
2386 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002387 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002388 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002389
reed@android.com8a1c16f2008-12-17 15:59:43 +00002390 matrix.setTranslate(hOffset, vOffset);
2391 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2392}
2393
reed@android.comf76bacf2009-05-13 14:00:33 +00002394///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002395void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002396 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002397 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002398 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002399 }
2400}
2401
reedd5fa1a42014-08-09 11:08:05 -07002402void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002403 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002404 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002405 if (matrix && matrix->isIdentity()) {
2406 matrix = NULL;
2407 }
2408 this->onDrawPicture(picture, matrix, paint);
2409 }
2410}
robertphillips9b14f262014-06-04 05:40:44 -07002411
reedd5fa1a42014-08-09 11:08:05 -07002412void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2413 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002414 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002415 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002416 // Canvas has to first give the device the opportunity to render
2417 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002418 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002419 return; // the device has rendered the entire picture
2420 }
2421 }
2422
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002423 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002424
robertphillipsc5ba71d2014-09-04 08:42:50 -07002425 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002426}
2427
reed@android.com8a1c16f2008-12-17 15:59:43 +00002428///////////////////////////////////////////////////////////////////////////////
2429///////////////////////////////////////////////////////////////////////////////
2430
2431SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002432 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002433
2434 SkASSERT(canvas);
2435
2436 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2437 fDone = !fImpl->next();
2438}
2439
2440SkCanvas::LayerIter::~LayerIter() {
2441 fImpl->~SkDrawIter();
2442}
2443
2444void SkCanvas::LayerIter::next() {
2445 fDone = !fImpl->next();
2446}
2447
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002448SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002449 return fImpl->getDevice();
2450}
2451
2452const SkMatrix& SkCanvas::LayerIter::matrix() const {
2453 return fImpl->getMatrix();
2454}
2455
2456const SkPaint& SkCanvas::LayerIter::paint() const {
2457 const SkPaint* paint = fImpl->getPaint();
2458 if (NULL == paint) {
2459 paint = &fDefaultPaint;
2460 }
2461 return *paint;
2462}
2463
2464const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2465int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2466int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002467
2468///////////////////////////////////////////////////////////////////////////////
2469
fmalitac3b589a2014-06-05 12:40:07 -07002470SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002471
2472///////////////////////////////////////////////////////////////////////////////
2473
2474static bool supported_for_raster_canvas(const SkImageInfo& info) {
2475 switch (info.alphaType()) {
2476 case kPremul_SkAlphaType:
2477 case kOpaque_SkAlphaType:
2478 break;
2479 default:
2480 return false;
2481 }
2482
2483 switch (info.colorType()) {
2484 case kAlpha_8_SkColorType:
2485 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002486 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002487 break;
2488 default:
2489 return false;
2490 }
2491
2492 return true;
2493}
2494
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002495SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2496 if (!supported_for_raster_canvas(info)) {
2497 return NULL;
2498 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002499
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002500 SkBitmap bitmap;
2501 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2502 return NULL;
2503 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002504 return SkNEW_ARGS(SkCanvas, (bitmap));
2505}
reedd5fa1a42014-08-09 11:08:05 -07002506
2507///////////////////////////////////////////////////////////////////////////////
2508
2509SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002510 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002511 : fCanvas(canvas)
2512 , fSaveCount(canvas->getSaveCount())
2513{
bsalomon49f085d2014-09-05 13:34:00 -07002514 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002515 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002516 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002517 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002518 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002519 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002520 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002521 canvas->save();
2522 }
mtklein6cfa73a2014-08-13 13:33:49 -07002523
bsalomon49f085d2014-09-05 13:34:00 -07002524 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002525 canvas->concat(*matrix);
2526 }
2527}
2528
2529SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2530 fCanvas->restoreToCount(fSaveCount);
2531}