blob: 8b88a038146c17b3c691ccbcf80c5ffa62422bfb [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
reedd9544982014-09-09 18:46:22 -0700117 DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas,
118 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
reed@google.com8926b162012-03-23 15:36:36 +0000298 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
299 SkPaint tmp;
300 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)) {
322 SkPaint* paint = fLazyPaint.set(fOrigPaint);
323 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:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000353 SkLazyPaint fLazyPaint;
354 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
374 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
reedd9544982014-09-09 18:46:22 -0700441 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, 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,
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000834 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000835 SkIRect clipBounds;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000836 SkRegion::Op op = SkRegion::kIntersect_Op;
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000837 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000838 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000839 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000840
841 if (imageFilter) {
reed1f836ee2014-07-07 07:49:34 -0700842 imageFilter->filterBounds(clipBounds, fMCRec->fMatrix, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000843 // Filters may grow the bounds beyond the device bounds.
844 op = SkRegion::kReplace_Op;
845 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000846 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700847 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000848 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000849
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850 this->getTotalMatrix().mapRect(&r, *bounds);
851 r.roundOut(&ir);
852 // early exit if the layer's bounds are clipped out
853 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000854 if (bounds_affects_clip(flags)) {
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 }
862
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000863 if (bounds_affects_clip(flags)) {
joshualittde358a92015-02-05 08:19:35 -0800864 fClipStack->clipDevRect(ir, op);
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000865 // early exit if the clip is now empty
reed1f836ee2014-07-07 07:49:34 -0700866 if (!fMCRec->fRasterClip.op(ir, op)) {
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000867 return false;
868 }
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);
reedd9544982014-09-09 18:46:22 -0700957 DeviceCM* layer = SkNEW_ARGS(DeviceCM,
958 (device, ir.fLeft, ir.fTop, paint, this, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000959 device->unref();
960
961 layer->fNext = fMCRec->fTopLayer;
962 fMCRec->fLayer = layer;
963 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964}
965
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000966int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
967 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
968}
969
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
971 SaveFlags flags) {
972 if (0xFF == alpha) {
973 return this->saveLayer(bounds, NULL, flags);
974 } else {
975 SkPaint tmpPaint;
976 tmpPaint.setAlpha(alpha);
977 return this->saveLayer(bounds, &tmpPaint, flags);
978 }
979}
980
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981void SkCanvas::internalRestore() {
982 SkASSERT(fMCStack.count() != 0);
983
984 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +0000985 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986
joshualittde358a92015-02-05 08:19:35 -0800987 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +0000988
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000989 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000990 DeviceCM* layer = fMCRec->fLayer; // may be null
991 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
992 fMCRec->fLayer = NULL;
993
994 // now do the normal restore()
995 fMCRec->~MCRec(); // balanced in save()
996 fMCStack.pop_back();
997 fMCRec = (MCRec*)fMCStack.back();
998
999 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1000 since if we're being recorded, we don't want to record this (the
1001 recorder will have already recorded the restore).
1002 */
bsalomon49f085d2014-09-05 13:34:00 -07001003 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001004 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001005 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001006 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1007 layer->fPaint);
1008 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001009 fDeviceCMDirty = true;
1010 }
1011 SkDELETE(layer);
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001012 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001013}
1014
reed4a8126e2014-09-22 07:29:03 -07001015SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1016 if (NULL == props) {
1017 props = &fProps;
1018 }
1019 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001020}
1021
reed4a8126e2014-09-22 07:29:03 -07001022SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001023 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001024 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001025}
1026
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001027SkImageInfo SkCanvas::imageInfo() const {
1028 SkBaseDevice* dev = this->getDevice();
1029 if (dev) {
1030 return dev->imageInfo();
1031 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001032 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001033 }
1034}
1035
1036const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1037 return this->onPeekPixels(info, rowBytes);
1038}
1039
1040const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1041 SkBaseDevice* dev = this->getDevice();
1042 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1043}
1044
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001045void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1046 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1047 if (pixels && origin) {
1048 *origin = this->getTopDevice(false)->getOrigin();
1049 }
1050 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001051}
1052
1053void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1054 SkBaseDevice* dev = this->getTopDevice();
1055 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1056}
1057
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001058SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1059 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1060 if (NULL == fAddr) {
1061 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001062 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001063 return; // failure, fAddr is NULL
1064 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001065 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1066 return; // failure, fAddr is NULL
1067 }
1068 fAddr = fBitmap.getPixels();
1069 fRowBytes = fBitmap.rowBytes();
1070 }
1071 SkASSERT(fAddr); // success
1072}
1073
1074bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1075 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001076 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001077 } else {
1078 bitmap->reset();
1079 return false;
1080 }
1081}
1082
reed@android.com8a1c16f2008-12-17 15:59:43 +00001083/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001084void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001085 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001086 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 return;
1088 }
1089
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001090 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001091 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001092 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001093 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001094
1095 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001096
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001097 SkRect storage;
1098 const SkRect* bounds = NULL;
1099 if (paint && paint->canComputeFastBounds()) {
1100 bitmap.getBounds(&storage);
1101 matrix.mapRect(&storage);
1102 bounds = &paint->computeFastBounds(storage, &storage);
1103 }
1104
1105 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001106
1107 while (iter.next()) {
1108 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1109 }
1110
1111 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001112}
1113
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001114void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed@google.com8926b162012-03-23 15:36:36 +00001115 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001116 SkPaint tmp;
1117 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001118 paint = &tmp;
1119 }
reed@google.com4b226022011-01-11 18:32:13 +00001120
reed@google.com8926b162012-03-23 15:36:36 +00001121 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001122 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001123 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001124 paint = &looper.paint();
1125 SkImageFilter* filter = paint->getImageFilter();
1126 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001127 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001128 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001129 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001130 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001131 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001132 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001133 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001134 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001135 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001136 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001137 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001138 SkPaint tmpUnfiltered(*paint);
1139 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001140 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1141 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001142 }
1143 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001144 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001145 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001146 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001147 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001148}
1149
reed41af9662015-01-05 07:49:08 -08001150void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001151 if (gTreatSpriteAsBitmap) {
1152 this->save();
1153 this->resetMatrix();
1154 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1155 this->restore();
1156 return;
1157 }
1158
danakj9881d632014-11-26 12:41:06 -08001159 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001160 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001161 return;
1162 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001163 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001164
reed@google.com8926b162012-03-23 15:36:36 +00001165 SkPaint tmp;
1166 if (NULL == paint) {
1167 paint = &tmp;
1168 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001169
reed@google.com8926b162012-03-23 15:36:36 +00001170 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001171
reed@google.com8926b162012-03-23 15:36:36 +00001172 while (iter.next()) {
1173 paint = &looper.paint();
1174 SkImageFilter* filter = paint->getImageFilter();
1175 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1176 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001177 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001178 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001179 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001180 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001181 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001182 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001183 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001184 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001185 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001186 SkPaint tmpUnfiltered(*paint);
1187 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001188 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001189 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001190 }
1191 } else {
1192 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1193 }
1194 }
1195 LOOPER_END
1196}
1197
reed@android.com8a1c16f2008-12-17 15:59:43 +00001198/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001199void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001200 SkMatrix m;
1201 m.setTranslate(dx, dy);
1202 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001203}
1204
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001205void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001206 SkMatrix m;
1207 m.setScale(sx, sy);
1208 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001209}
1210
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001211void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001212 SkMatrix m;
1213 m.setRotate(degrees);
1214 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001215}
1216
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001217void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001218 SkMatrix m;
1219 m.setSkew(sx, sy);
1220 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001221}
1222
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001223void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001224 if (matrix.isIdentity()) {
1225 return;
1226 }
1227
reed2ff1fce2014-12-11 07:07:37 -08001228 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001229 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001230 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001231 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001232
1233 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001234}
1235
reed@android.com8a1c16f2008-12-17 15:59:43 +00001236void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001237 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001238 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001239 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001240 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001241 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001242}
1243
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244void SkCanvas::resetMatrix() {
1245 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001246
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247 matrix.reset();
1248 this->setMatrix(matrix);
1249}
1250
1251//////////////////////////////////////////////////////////////////////////////
1252
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001253void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001254 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001255 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1256 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001257}
1258
1259void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001260#ifdef SK_ENABLE_CLIP_QUICKREJECT
1261 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001262 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001263 return false;
1264 }
1265
reed@google.com3b3e8952012-08-16 20:53:31 +00001266 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001267 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001268 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001269
1270 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001271 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001272 }
1273 }
1274#endif
1275
reed@google.com5c3d1472011-02-22 19:12:23 +00001276 AutoValidateClip avc(this);
1277
reed@android.com8a1c16f2008-12-17 15:59:43 +00001278 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001279 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001280 if (!fAllowSoftClip) {
1281 edgeStyle = kHard_ClipEdgeStyle;
1282 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283
reed1f836ee2014-07-07 07:49:34 -07001284 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001285 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001286 // the matrix. This means we don't have to a) make a path, and b) tell
1287 // the region code to scan-convert the path, only to discover that it
1288 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001289 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290
reed1f836ee2014-07-07 07:49:34 -07001291 fMCRec->fMatrix.mapRect(&r, rect);
joshualittde358a92015-02-05 08:19:35 -08001292 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001293 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001294 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001295 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001296 // and clip against that, since it can handle any matrix. However, to
1297 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1298 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299 SkPath path;
1300
1301 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001302 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001303 }
1304}
1305
reed73e714e2014-09-04 09:02:23 -07001306static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1307 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001308 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001309}
1310
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001311void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001312 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001313 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001314 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001315 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1316 } else {
1317 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001318 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001319}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001320
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001321void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001322 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001323 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001324 AutoValidateClip avc(this);
1325
1326 fDeviceCMDirty = true;
1327 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001328 if (!fAllowSoftClip) {
1329 edgeStyle = kHard_ClipEdgeStyle;
1330 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001331
joshualittde358a92015-02-05 08:19:35 -08001332 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001333
1334 SkPath devPath;
1335 devPath.addRRect(transformedRRect);
1336
reed73e714e2014-09-04 09:02:23 -07001337 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001338 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001339 }
1340
1341 SkPath path;
1342 path.addRRect(rrect);
1343 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001344 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001345}
1346
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001347void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001348 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001349 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1350 SkRect r;
1351 if (!path.isInverseFillType() && path.isRect(&r)) {
1352 this->onClipRect(r, op, edgeStyle);
1353 } else {
1354 this->onClipPath(path, op, edgeStyle);
1355 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001356}
1357
1358void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001359#ifdef SK_ENABLE_CLIP_QUICKREJECT
1360 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001361 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001362 return false;
1363 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001364
reed@google.com3b3e8952012-08-16 20:53:31 +00001365 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001366 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001367 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001368
reed@google.comda17f752012-08-16 18:27:05 +00001369 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001370 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001371 }
1372 }
1373#endif
1374
reed@google.com5c3d1472011-02-22 19:12:23 +00001375 AutoValidateClip avc(this);
1376
reed@android.com8a1c16f2008-12-17 15:59:43 +00001377 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001378 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001379 if (!fAllowSoftClip) {
1380 edgeStyle = kHard_ClipEdgeStyle;
1381 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001382
1383 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001384 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385
reed@google.comfe701122011-11-08 19:41:23 +00001386 // Check if the transfomation, or the original path itself
1387 // made us empty. Note this can also happen if we contained NaN
1388 // values. computing the bounds detects this, and will set our
1389 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1390 if (devPath.getBounds().isEmpty()) {
1391 // resetting the path will remove any NaN or other wanky values
1392 // that might upset our scan converter.
1393 devPath.reset();
1394 }
1395
reed@google.com5c3d1472011-02-22 19:12:23 +00001396 // if we called path.swap() we could avoid a deep copy of this path
joshualittde358a92015-02-05 08:19:35 -08001397 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001398
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001399 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001400 bool clipIsAA = getClipStack()->asPath(&devPath);
1401 if (clipIsAA) {
1402 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001403 }
fmalita1a481fe2015-02-04 07:39:34 -08001404
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001405 op = SkRegion::kReplace_Op;
1406 }
1407
reed73e714e2014-09-04 09:02:23 -07001408 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409}
1410
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001411void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001412 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001413 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001414}
1415
1416void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001417 AutoValidateClip avc(this);
1418
reed@android.com8a1c16f2008-12-17 15:59:43 +00001419 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001420 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001421
reed@google.com5c3d1472011-02-22 19:12:23 +00001422 // todo: signal fClipStack that we have a region, and therefore (I guess)
1423 // we have to ignore it, and use the region directly?
joshualittde358a92015-02-05 08:19:35 -08001424 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001425
reed1f836ee2014-07-07 07:49:34 -07001426 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001427}
1428
reed@google.com819c9212011-02-23 18:56:55 +00001429#ifdef SK_DEBUG
1430void SkCanvas::validateClip() const {
1431 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001432 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001433 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001434 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001435 return;
1436 }
1437
reed@google.com819c9212011-02-23 18:56:55 +00001438 SkIRect ir;
1439 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001440 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001441
joshualittde358a92015-02-05 08:19:35 -08001442 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001443 const SkClipStack::Element* element;
1444 while ((element = iter.next()) != NULL) {
1445 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001446 case SkClipStack::Element::kRect_Type:
1447 element->getRect().round(&ir);
1448 tmpClip.op(ir, element->getOp());
1449 break;
1450 case SkClipStack::Element::kEmpty_Type:
1451 tmpClip.setEmpty();
1452 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001453 default: {
1454 SkPath path;
1455 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001456 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001457 break;
1458 }
reed@google.com819c9212011-02-23 18:56:55 +00001459 }
1460 }
reed@google.com819c9212011-02-23 18:56:55 +00001461}
1462#endif
1463
reed@google.com90c07ea2012-04-13 13:50:27 +00001464void SkCanvas::replayClips(ClipVisitor* visitor) const {
joshualittde358a92015-02-05 08:19:35 -08001465 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001466 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001467
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001468 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001469 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001470 }
1471}
1472
reed@google.com5c3d1472011-02-22 19:12:23 +00001473///////////////////////////////////////////////////////////////////////////////
1474
reed@google.com754de5f2014-02-24 19:38:20 +00001475bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001476 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001477}
1478
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001479bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001480 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001481}
1482
reed@google.com3b3e8952012-08-16 20:53:31 +00001483bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001484 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001485 return true;
1486
reed1f836ee2014-07-07 07:49:34 -07001487 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001488 return true;
1489 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001490
reed1f836ee2014-07-07 07:49:34 -07001491 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001492 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001493 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001494 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001495 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001496 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001497
reed@android.coma380ae42009-07-21 01:17:02 +00001498 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001499 // TODO: should we use | instead, or compare all 4 at once?
1500 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001501 return true;
1502 }
reed@google.comc0784db2013-12-13 21:16:12 +00001503 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001504 return true;
1505 }
1506 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001507 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508}
1509
reed@google.com3b3e8952012-08-16 20:53:31 +00001510bool SkCanvas::quickReject(const SkPath& path) const {
1511 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001512}
1513
reed@google.com3b3e8952012-08-16 20:53:31 +00001514bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001515 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001516 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001517 return false;
1518 }
1519
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001520 SkMatrix inverse;
1521 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001522 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001523 if (bounds) {
1524 bounds->setEmpty();
1525 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001526 return false;
1527 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001528
bsalomon49f085d2014-09-05 13:34:00 -07001529 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001530 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001531 // adjust it outwards in case we are antialiasing
1532 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001533
reed@google.com8f4d2302013-12-17 16:44:46 +00001534 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1535 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001536 inverse.mapRect(bounds, r);
1537 }
1538 return true;
1539}
1540
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001541bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001542 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001543 if (clip.isEmpty()) {
1544 if (bounds) {
1545 bounds->setEmpty();
1546 }
1547 return false;
1548 }
1549
bsalomon49f085d2014-09-05 13:34:00 -07001550 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001551 *bounds = clip.getBounds();
1552 }
1553 return true;
1554}
1555
reed@android.com8a1c16f2008-12-17 15:59:43 +00001556const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001557 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001558}
1559
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001560const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001561 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001562}
1563
reed@google.com9c135db2014-03-12 18:28:35 +00001564GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1565 SkBaseDevice* dev = this->getTopDevice();
1566 return dev ? dev->accessRenderTarget() : NULL;
1567}
1568
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001569GrContext* SkCanvas::getGrContext() {
1570#if SK_SUPPORT_GPU
1571 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001572 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001573 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001574 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001575 return renderTarget->getContext();
1576 }
1577 }
1578#endif
1579
1580 return NULL;
1581
1582}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001583
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001584void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1585 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001586 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001587 if (outer.isEmpty()) {
1588 return;
1589 }
1590 if (inner.isEmpty()) {
1591 this->drawRRect(outer, paint);
1592 return;
1593 }
1594
1595 // We don't have this method (yet), but technically this is what we should
1596 // be able to assert...
1597 // SkASSERT(outer.contains(inner));
1598 //
1599 // For now at least check for containment of bounds
1600 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1601
1602 this->onDrawDRRect(outer, inner, paint);
1603}
1604
reed41af9662015-01-05 07:49:08 -08001605// These need to stop being virtual -- clients need to override the onDraw... versions
1606
1607void SkCanvas::drawPaint(const SkPaint& paint) {
1608 this->onDrawPaint(paint);
1609}
1610
1611void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1612 this->onDrawRect(r, paint);
1613}
1614
1615void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1616 this->onDrawOval(r, paint);
1617}
1618
1619void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1620 this->onDrawRRect(rrect, paint);
1621}
1622
1623void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1624 this->onDrawPoints(mode, count, pts, paint);
1625}
1626
1627void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1628 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1629 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1630 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1631 indices, indexCount, paint);
1632}
1633
1634void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1635 this->onDrawPath(path, paint);
1636}
1637
1638void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1639 this->onDrawImage(image, dx, dy, paint);
1640}
1641
1642void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1643 const SkPaint* paint) {
1644 this->onDrawImageRect(image, src, dst, paint);
1645}
1646
1647void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1648 this->onDrawBitmap(bitmap, dx, dy, paint);
1649}
1650
1651void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1652 const SkPaint* paint, DrawBitmapRectFlags flags) {
1653 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1654}
1655
1656void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1657 const SkPaint* paint) {
1658 this->onDrawBitmapNine(bitmap, center, dst, paint);
1659}
1660
1661void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
1662 this->onDrawSprite(bitmap, left, top, paint);
1663}
1664
reed@android.com8a1c16f2008-12-17 15:59:43 +00001665//////////////////////////////////////////////////////////////////////////////
1666// These are the virtual drawing methods
1667//////////////////////////////////////////////////////////////////////////////
1668
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001669void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001670 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001671 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1672 }
1673}
1674
reed41af9662015-01-05 07:49:08 -08001675void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001676 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001677 this->internalDrawPaint(paint);
1678}
1679
1680void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001681 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001682
1683 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001684 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001685 }
1686
reed@google.com4e2b3d32011-04-07 14:18:59 +00001687 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001688}
1689
reed41af9662015-01-05 07:49:08 -08001690void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1691 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001692 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001693 if ((long)count <= 0) {
1694 return;
1695 }
1696
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001697 SkRect r, storage;
1698 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001699 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001700 // special-case 2 points (common for drawing a single line)
1701 if (2 == count) {
1702 r.set(pts[0], pts[1]);
1703 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001704 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001705 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001706 bounds = &paint.computeFastStrokeBounds(r, &storage);
1707 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001708 return;
1709 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001710 }
reed@google.coma584aed2012-05-16 14:06:02 +00001711
reed@android.com8a1c16f2008-12-17 15:59:43 +00001712 SkASSERT(pts != NULL);
1713
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001714 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001715
reed@android.com8a1c16f2008-12-17 15:59:43 +00001716 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001717 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001718 }
reed@google.com4b226022011-01-11 18:32:13 +00001719
reed@google.com4e2b3d32011-04-07 14:18:59 +00001720 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001721}
1722
reed41af9662015-01-05 07:49:08 -08001723void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001724 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001725 SkRect storage;
1726 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001727 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001728 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1729 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1730 SkRect tmp(r);
1731 tmp.sort();
1732
1733 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001734 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001735 return;
1736 }
1737 }
reed@google.com4b226022011-01-11 18:32:13 +00001738
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001739 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001740
1741 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001742 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001743 }
1744
reed@google.com4e2b3d32011-04-07 14:18:59 +00001745 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001746}
1747
reed41af9662015-01-05 07:49:08 -08001748void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001749 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001750 SkRect storage;
1751 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001752 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001753 bounds = &paint.computeFastBounds(oval, &storage);
1754 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001755 return;
1756 }
1757 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001758
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001759 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001760
1761 while (iter.next()) {
1762 iter.fDevice->drawOval(iter, oval, looper.paint());
1763 }
1764
1765 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001766}
1767
reed41af9662015-01-05 07:49:08 -08001768void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001769 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001770 SkRect storage;
1771 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001772 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001773 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1774 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001775 return;
1776 }
1777 }
1778
1779 if (rrect.isRect()) {
1780 // call the non-virtual version
1781 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001782 return;
1783 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001784 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001785 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1786 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001787 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001788
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001789 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001790
1791 while (iter.next()) {
1792 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1793 }
1794
1795 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001796}
1797
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001798void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1799 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001800 SkRect storage;
1801 const SkRect* bounds = NULL;
1802 if (paint.canComputeFastBounds()) {
1803 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1804 if (this->quickReject(*bounds)) {
1805 return;
1806 }
1807 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001808
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001809 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001810
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001811 while (iter.next()) {
1812 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1813 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001814
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001815 LOOPER_END
1816}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001817
reed41af9662015-01-05 07:49:08 -08001818void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001819 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001820 if (!path.isFinite()) {
1821 return;
1822 }
1823
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001824 SkRect storage;
1825 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001826 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001827 const SkRect& pathBounds = path.getBounds();
1828 bounds = &paint.computeFastBounds(pathBounds, &storage);
1829 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001830 return;
1831 }
1832 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001833
1834 const SkRect& r = path.getBounds();
1835 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001836 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001837 this->internalDrawPaint(paint);
1838 }
1839 return;
1840 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001841
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001842 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001843
1844 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001845 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001846 }
1847
reed@google.com4e2b3d32011-04-07 14:18:59 +00001848 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001849}
1850
reed41af9662015-01-05 07:49:08 -08001851void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001852 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reed41af9662015-01-05 07:49:08 -08001853 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001854}
1855
reed41af9662015-01-05 07:49:08 -08001856void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1857 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001858 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
piotaixr5ceff912014-09-26 07:36:26 -07001859 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001860}
1861
reed41af9662015-01-05 07:49:08 -08001862void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001863 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001864 SkDEBUGCODE(bitmap.validate();)
1865
reed@google.com3d608122011-11-21 15:16:16 +00001866 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001867 SkRect bounds = {
1868 x, y,
1869 x + SkIntToScalar(bitmap.width()),
1870 y + SkIntToScalar(bitmap.height())
1871 };
1872 if (paint) {
1873 (void)paint->computeFastBounds(bounds, &bounds);
1874 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001875 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001876 return;
1877 }
1878 }
reed@google.com4b226022011-01-11 18:32:13 +00001879
reed@android.com8a1c16f2008-12-17 15:59:43 +00001880 SkMatrix matrix;
1881 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001882 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001883}
1884
reed@google.com9987ec32011-09-07 11:57:52 +00001885// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00001886void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001887 const SkRect& dst, const SkPaint* paint,
1888 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001889 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001890 return;
1891 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001892
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001893 SkRect storage;
1894 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00001895 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001896 if (paint) {
1897 bounds = &paint->computeFastBounds(dst, &storage);
1898 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001899 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001900 return;
1901 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001902 }
reed@google.com3d608122011-11-21 15:16:16 +00001903
reed@google.com33535f32012-09-25 15:37:50 +00001904 SkLazyPaint lazy;
1905 if (NULL == paint) {
1906 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001907 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001908
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001909 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001910
reed@google.com33535f32012-09-25 15:37:50 +00001911 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001912 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00001913 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001914
reed@google.com33535f32012-09-25 15:37:50 +00001915 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001916}
1917
reed41af9662015-01-05 07:49:08 -08001918void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1919 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08001920 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00001921 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001922 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00001923}
1924
reed@google.com9987ec32011-09-07 11:57:52 +00001925void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1926 const SkIRect& center, const SkRect& dst,
1927 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001928 if (bitmap.drawsNothing()) {
1929 return;
1930 }
reed@google.com3d608122011-11-21 15:16:16 +00001931 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00001932 SkRect storage;
1933 const SkRect* bounds = &dst;
1934 if (paint) {
1935 bounds = &paint->computeFastBounds(dst, &storage);
1936 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001937 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001938 return;
1939 }
1940 }
1941
reed@google.com9987ec32011-09-07 11:57:52 +00001942 const int32_t w = bitmap.width();
1943 const int32_t h = bitmap.height();
1944
1945 SkIRect c = center;
1946 // pin center to the bounds of the bitmap
1947 c.fLeft = SkMax32(0, center.fLeft);
1948 c.fTop = SkMax32(0, center.fTop);
1949 c.fRight = SkPin32(center.fRight, c.fLeft, w);
1950 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1951
reed@google.com71121732012-09-18 15:14:33 +00001952 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001953 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00001954 };
1955 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001956 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00001957 };
reed@google.com9987ec32011-09-07 11:57:52 +00001958 SkScalar dstX[4] = {
1959 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
1960 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
1961 };
1962 SkScalar dstY[4] = {
1963 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
1964 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
1965 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001966
reed@google.com9987ec32011-09-07 11:57:52 +00001967 if (dstX[1] > dstX[2]) {
1968 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
1969 dstX[2] = dstX[1];
1970 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001971
reed@google.com9987ec32011-09-07 11:57:52 +00001972 if (dstY[1] > dstY[2]) {
1973 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
1974 dstY[2] = dstY[1];
1975 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001976
reed@google.com9987ec32011-09-07 11:57:52 +00001977 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00001978 SkRect s, d;
1979
reed@google.com9987ec32011-09-07 11:57:52 +00001980 s.fTop = srcY[y];
1981 s.fBottom = srcY[y+1];
1982 d.fTop = dstY[y];
1983 d.fBottom = dstY[y+1];
1984 for (int x = 0; x < 3; x++) {
1985 s.fLeft = srcX[x];
1986 s.fRight = srcX[x+1];
1987 d.fLeft = dstX[x];
1988 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001989 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00001990 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00001991 }
1992 }
1993}
1994
reed41af9662015-01-05 07:49:08 -08001995void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1996 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001997 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00001998 SkDEBUGCODE(bitmap.validate();)
1999
2000 // Need a device entry-point, so gpu can use a mesh
2001 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2002}
2003
reed@google.comf67e4cf2011-03-15 20:56:58 +00002004class SkDeviceFilteredPaint {
2005public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002006 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002007 uint32_t filteredFlags = device->filterTextFlags(paint);
2008 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002009 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002010 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002011 fPaint = newPaint;
2012 } else {
2013 fPaint = &paint;
2014 }
2015 }
2016
reed@google.comf67e4cf2011-03-15 20:56:58 +00002017 const SkPaint& paint() const { return *fPaint; }
2018
2019private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002020 const SkPaint* fPaint;
2021 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002022};
2023
bungeman@google.com52c748b2011-08-22 21:30:43 +00002024void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2025 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002026 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002027 draw.fDevice->drawRect(draw, r, paint);
2028 } else {
2029 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002030 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002031 draw.fDevice->drawRect(draw, r, p);
2032 }
2033}
2034
2035void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2036 const char text[], size_t byteLength,
2037 SkScalar x, SkScalar y) {
2038 SkASSERT(byteLength == 0 || text != NULL);
2039
2040 // nothing to draw
2041 if (text == NULL || byteLength == 0 ||
2042 draw.fClip->isEmpty() ||
2043 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2044 return;
2045 }
2046
2047 SkScalar width = 0;
2048 SkPoint start;
2049
2050 start.set(0, 0); // to avoid warning
2051 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2052 SkPaint::kStrikeThruText_Flag)) {
2053 width = paint.measureText(text, byteLength);
2054
2055 SkScalar offsetX = 0;
2056 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2057 offsetX = SkScalarHalf(width);
2058 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2059 offsetX = width;
2060 }
2061 start.set(x - offsetX, y);
2062 }
2063
2064 if (0 == width) {
2065 return;
2066 }
2067
2068 uint32_t flags = paint.getFlags();
2069
2070 if (flags & (SkPaint::kUnderlineText_Flag |
2071 SkPaint::kStrikeThruText_Flag)) {
2072 SkScalar textSize = paint.getTextSize();
2073 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2074 SkRect r;
2075
2076 r.fLeft = start.fX;
2077 r.fRight = start.fX + width;
2078
2079 if (flags & SkPaint::kUnderlineText_Flag) {
2080 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2081 start.fY);
2082 r.fTop = offset;
2083 r.fBottom = offset + height;
2084 DrawRect(draw, paint, r, textSize);
2085 }
2086 if (flags & SkPaint::kStrikeThruText_Flag) {
2087 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2088 start.fY);
2089 r.fTop = offset;
2090 r.fBottom = offset + height;
2091 DrawRect(draw, paint, r, textSize);
2092 }
2093 }
2094}
2095
reed@google.come0d9ce82014-04-23 04:00:17 +00002096void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2097 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002098 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002099
2100 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002101 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002102 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002103 DrawTextDecorations(iter, dfp.paint(),
2104 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002105 }
2106
reed@google.com4e2b3d32011-04-07 14:18:59 +00002107 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002108}
2109
reed@google.come0d9ce82014-04-23 04:00:17 +00002110void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2111 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002112 SkPoint textOffset = SkPoint::Make(0, 0);
2113
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002114 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002115
reed@android.com8a1c16f2008-12-17 15:59:43 +00002116 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002117 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002118 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002119 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002120 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002121
reed@google.com4e2b3d32011-04-07 14:18:59 +00002122 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002123}
2124
reed@google.come0d9ce82014-04-23 04:00:17 +00002125void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2126 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002127
2128 SkPoint textOffset = SkPoint::Make(0, constY);
2129
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002130 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002131
reed@android.com8a1c16f2008-12-17 15:59:43 +00002132 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002133 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002134 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002135 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002136 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002137
reed@google.com4e2b3d32011-04-07 14:18:59 +00002138 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002139}
2140
reed@google.come0d9ce82014-04-23 04:00:17 +00002141void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2142 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002143 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002144
reed@android.com8a1c16f2008-12-17 15:59:43 +00002145 while (iter.next()) {
2146 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002147 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002148 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002149
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002150 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002151}
2152
fmalita00d5c2c2014-08-21 08:53:26 -07002153void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2154 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002155
fmalita19653d12014-10-16 11:53:30 -07002156 if (paint.canComputeFastBounds()) {
fmalita7ba7aa72014-08-29 09:46:36 -07002157 SkRect storage;
2158
2159 if (this->quickReject(paint.computeFastBounds(blob->bounds().makeOffset(x, y), &storage))) {
2160 return;
2161 }
2162 }
2163
fmalita024f9962015-03-03 19:08:17 -08002164 // We cannot filter in the looper as we normally do, because the paint is
2165 // incomplete at this point (text-related attributes are embedded within blob run paints).
2166 SkDrawFilter* drawFilter = fMCRec->fFilter;
2167 fMCRec->fFilter = NULL;
2168
fmalitaaa1b9122014-08-28 14:32:24 -07002169 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
fmalita00d5c2c2014-08-21 08:53:26 -07002170
fmalitaaa1b9122014-08-28 14:32:24 -07002171 while (iter.next()) {
2172 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002173 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002174 }
2175
fmalitaaa1b9122014-08-28 14:32:24 -07002176 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002177
2178 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002179}
2180
reed@google.come0d9ce82014-04-23 04:00:17 +00002181// These will become non-virtual, so they always call the (virtual) onDraw... method
2182void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2183 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002184 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002185 this->onDrawText(text, byteLength, x, y, paint);
2186}
2187void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2188 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002189 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002190 this->onDrawPosText(text, byteLength, pos, paint);
2191}
2192void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2193 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002194 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002195 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2196}
2197void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2198 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002199 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002200 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2201}
fmalita00d5c2c2014-08-21 08:53:26 -07002202void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2203 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002204 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002205 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002206 this->onDrawTextBlob(blob, x, y, paint);
2207 }
2208}
reed@google.come0d9ce82014-04-23 04:00:17 +00002209
reed41af9662015-01-05 07:49:08 -08002210void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2211 const SkPoint verts[], const SkPoint texs[],
2212 const SkColor colors[], SkXfermode* xmode,
2213 const uint16_t indices[], int indexCount,
2214 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002215 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002216 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002217
reed@android.com8a1c16f2008-12-17 15:59:43 +00002218 while (iter.next()) {
2219 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002220 colors, xmode, indices, indexCount,
2221 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002222 }
reed@google.com4b226022011-01-11 18:32:13 +00002223
reed@google.com4e2b3d32011-04-07 14:18:59 +00002224 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002225}
2226
dandovb3c9d1c2014-08-12 08:34:29 -07002227void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2228 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002229 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002230 if (NULL == cubics) {
2231 return;
2232 }
mtklein6cfa73a2014-08-13 13:33:49 -07002233
dandovecfff212014-08-04 10:02:00 -07002234 // Since a patch is always within the convex hull of the control points, we discard it when its
2235 // bounding rectangle is completely outside the current clip.
2236 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002237 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002238 if (this->quickReject(bounds)) {
2239 return;
2240 }
mtklein6cfa73a2014-08-13 13:33:49 -07002241
dandovb3c9d1c2014-08-12 08:34:29 -07002242 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2243}
2244
2245void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2246 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2247
dandovecfff212014-08-04 10:02:00 -07002248 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002249
dandovecfff212014-08-04 10:02:00 -07002250 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002251 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002252 }
mtklein6cfa73a2014-08-13 13:33:49 -07002253
dandovecfff212014-08-04 10:02:00 -07002254 LOOPER_END
2255}
2256
reed3cb38402015-02-06 08:36:15 -08002257void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002258 if (dr && !this->quickReject(dr->getBounds())) {
2259 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002260 }
2261}
2262
reed3cb38402015-02-06 08:36:15 -08002263void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002264 dr->draw(this);
2265}
2266
reed@android.com8a1c16f2008-12-17 15:59:43 +00002267//////////////////////////////////////////////////////////////////////////////
2268// These methods are NOT virtual, and therefore must call back into virtual
2269// methods, rather than actually drawing themselves.
2270//////////////////////////////////////////////////////////////////////////////
2271
2272void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002273 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002274 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002275 SkPaint paint;
2276
2277 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002278 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002279 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002280 }
2281 this->drawPaint(paint);
2282}
2283
reed@android.com845fdac2009-06-23 03:01:32 +00002284void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002285 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002286 SkPaint paint;
2287
2288 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002289 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002290 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002291 }
2292 this->drawPaint(paint);
2293}
2294
2295void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002296 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002297 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002298
reed@android.com8a1c16f2008-12-17 15:59:43 +00002299 pt.set(x, y);
2300 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2301}
2302
2303void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002304 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305 SkPoint pt;
2306 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002307
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308 pt.set(x, y);
2309 paint.setColor(color);
2310 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2311}
2312
2313void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2314 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002315 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002316 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002317
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318 pts[0].set(x0, y0);
2319 pts[1].set(x1, y1);
2320 this->drawPoints(kLines_PointMode, 2, pts, paint);
2321}
2322
2323void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2324 SkScalar right, SkScalar bottom,
2325 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002326 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002327 SkRect r;
2328
2329 r.set(left, top, right, bottom);
2330 this->drawRect(r, paint);
2331}
2332
2333void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2334 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002335 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002336 if (radius < 0) {
2337 radius = 0;
2338 }
2339
2340 SkRect r;
2341 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002342 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002343}
2344
2345void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2346 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002347 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002348 if (rx > 0 && ry > 0) {
2349 if (paint.canComputeFastBounds()) {
2350 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002351 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002352 return;
2353 }
2354 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002355 SkRRect rrect;
2356 rrect.setRectXY(r, rx, ry);
2357 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002358 } else {
2359 this->drawRect(r, paint);
2360 }
2361}
2362
reed@android.com8a1c16f2008-12-17 15:59:43 +00002363void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2364 SkScalar sweepAngle, bool useCenter,
2365 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002366 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002367 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2368 this->drawOval(oval, paint);
2369 } else {
2370 SkPath path;
2371 if (useCenter) {
2372 path.moveTo(oval.centerX(), oval.centerY());
2373 }
2374 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2375 if (useCenter) {
2376 path.close();
2377 }
2378 this->drawPath(path, paint);
2379 }
2380}
2381
2382void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2383 const SkPath& path, SkScalar hOffset,
2384 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002385 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002386 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002387
reed@android.com8a1c16f2008-12-17 15:59:43 +00002388 matrix.setTranslate(hOffset, vOffset);
2389 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2390}
2391
reed@android.comf76bacf2009-05-13 14:00:33 +00002392///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002393void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002394 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002395 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002396 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002397 }
2398}
2399
reedd5fa1a42014-08-09 11:08:05 -07002400void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002401 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002402 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002403 if (matrix && matrix->isIdentity()) {
2404 matrix = NULL;
2405 }
2406 this->onDrawPicture(picture, matrix, paint);
2407 }
2408}
robertphillips9b14f262014-06-04 05:40:44 -07002409
reedd5fa1a42014-08-09 11:08:05 -07002410void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2411 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002412 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002413 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002414 // Canvas has to first give the device the opportunity to render
2415 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002416 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002417 return; // the device has rendered the entire picture
2418 }
2419 }
2420
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002421 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002422
robertphillipsc5ba71d2014-09-04 08:42:50 -07002423 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002424}
2425
reed@android.com8a1c16f2008-12-17 15:59:43 +00002426///////////////////////////////////////////////////////////////////////////////
2427///////////////////////////////////////////////////////////////////////////////
2428
2429SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002430 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002431
2432 SkASSERT(canvas);
2433
2434 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2435 fDone = !fImpl->next();
2436}
2437
2438SkCanvas::LayerIter::~LayerIter() {
2439 fImpl->~SkDrawIter();
2440}
2441
2442void SkCanvas::LayerIter::next() {
2443 fDone = !fImpl->next();
2444}
2445
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002446SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002447 return fImpl->getDevice();
2448}
2449
2450const SkMatrix& SkCanvas::LayerIter::matrix() const {
2451 return fImpl->getMatrix();
2452}
2453
2454const SkPaint& SkCanvas::LayerIter::paint() const {
2455 const SkPaint* paint = fImpl->getPaint();
2456 if (NULL == paint) {
2457 paint = &fDefaultPaint;
2458 }
2459 return *paint;
2460}
2461
2462const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2463int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2464int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002465
2466///////////////////////////////////////////////////////////////////////////////
2467
fmalitac3b589a2014-06-05 12:40:07 -07002468SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002469
2470///////////////////////////////////////////////////////////////////////////////
2471
2472static bool supported_for_raster_canvas(const SkImageInfo& info) {
2473 switch (info.alphaType()) {
2474 case kPremul_SkAlphaType:
2475 case kOpaque_SkAlphaType:
2476 break;
2477 default:
2478 return false;
2479 }
2480
2481 switch (info.colorType()) {
2482 case kAlpha_8_SkColorType:
2483 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002484 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002485 break;
2486 default:
2487 return false;
2488 }
2489
2490 return true;
2491}
2492
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002493SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2494 if (!supported_for_raster_canvas(info)) {
2495 return NULL;
2496 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002497
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002498 SkBitmap bitmap;
2499 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2500 return NULL;
2501 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002502 return SkNEW_ARGS(SkCanvas, (bitmap));
2503}
reedd5fa1a42014-08-09 11:08:05 -07002504
2505///////////////////////////////////////////////////////////////////////////////
2506
2507SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002508 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002509 : fCanvas(canvas)
2510 , fSaveCount(canvas->getSaveCount())
2511{
bsalomon49f085d2014-09-05 13:34:00 -07002512 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002513 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002514 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002515 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002516 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002517 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002518 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002519 canvas->save();
2520 }
mtklein6cfa73a2014-08-13 13:33:49 -07002521
bsalomon49f085d2014-09-05 13:34:00 -07002522 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002523 canvas->concat(*matrix);
2524 }
2525}
2526
2527SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2528 fCanvas->restoreToCount(fSaveCount);
2529}