blob: a47bd89c0507acad23ca7512279813ddd4a8697f [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
fmalita85d5eb92015-03-04 11:20:12 -08002156 SkRect storage;
2157 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002158 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002159 storage = blob->bounds().makeOffset(x, y);
2160 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002161
fmalita85d5eb92015-03-04 11:20:12 -08002162 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002163 return;
2164 }
2165 }
2166
fmalita024f9962015-03-03 19:08:17 -08002167 // We cannot filter in the looper as we normally do, because the paint is
2168 // incomplete at this point (text-related attributes are embedded within blob run paints).
2169 SkDrawFilter* drawFilter = fMCRec->fFilter;
2170 fMCRec->fFilter = NULL;
2171
fmalita85d5eb92015-03-04 11:20:12 -08002172 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002173
fmalitaaa1b9122014-08-28 14:32:24 -07002174 while (iter.next()) {
2175 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002176 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002177 }
2178
fmalitaaa1b9122014-08-28 14:32:24 -07002179 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002180
2181 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002182}
2183
reed@google.come0d9ce82014-04-23 04:00:17 +00002184// These will become non-virtual, so they always call the (virtual) onDraw... method
2185void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2186 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002187 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002188 this->onDrawText(text, byteLength, x, y, paint);
2189}
2190void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2191 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002192 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002193 this->onDrawPosText(text, byteLength, pos, paint);
2194}
2195void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2196 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002197 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002198 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2199}
2200void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2201 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002202 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002203 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2204}
fmalita00d5c2c2014-08-21 08:53:26 -07002205void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2206 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002207 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002208 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002209 this->onDrawTextBlob(blob, x, y, paint);
2210 }
2211}
reed@google.come0d9ce82014-04-23 04:00:17 +00002212
reed41af9662015-01-05 07:49:08 -08002213void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2214 const SkPoint verts[], const SkPoint texs[],
2215 const SkColor colors[], SkXfermode* xmode,
2216 const uint16_t indices[], int indexCount,
2217 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002218 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002219 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002220
reed@android.com8a1c16f2008-12-17 15:59:43 +00002221 while (iter.next()) {
2222 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002223 colors, xmode, indices, indexCount,
2224 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002225 }
reed@google.com4b226022011-01-11 18:32:13 +00002226
reed@google.com4e2b3d32011-04-07 14:18:59 +00002227 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002228}
2229
dandovb3c9d1c2014-08-12 08:34:29 -07002230void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2231 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002232 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002233 if (NULL == cubics) {
2234 return;
2235 }
mtklein6cfa73a2014-08-13 13:33:49 -07002236
dandovecfff212014-08-04 10:02:00 -07002237 // Since a patch is always within the convex hull of the control points, we discard it when its
2238 // bounding rectangle is completely outside the current clip.
2239 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002240 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002241 if (this->quickReject(bounds)) {
2242 return;
2243 }
mtklein6cfa73a2014-08-13 13:33:49 -07002244
dandovb3c9d1c2014-08-12 08:34:29 -07002245 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2246}
2247
2248void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2249 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2250
dandovecfff212014-08-04 10:02:00 -07002251 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002252
dandovecfff212014-08-04 10:02:00 -07002253 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002254 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002255 }
mtklein6cfa73a2014-08-13 13:33:49 -07002256
dandovecfff212014-08-04 10:02:00 -07002257 LOOPER_END
2258}
2259
reed3cb38402015-02-06 08:36:15 -08002260void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002261 if (dr && !this->quickReject(dr->getBounds())) {
2262 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002263 }
2264}
2265
reed3cb38402015-02-06 08:36:15 -08002266void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002267 dr->draw(this);
2268}
2269
reed@android.com8a1c16f2008-12-17 15:59:43 +00002270//////////////////////////////////////////////////////////////////////////////
2271// These methods are NOT virtual, and therefore must call back into virtual
2272// methods, rather than actually drawing themselves.
2273//////////////////////////////////////////////////////////////////////////////
2274
2275void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002276 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002277 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002278 SkPaint paint;
2279
2280 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002281 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002282 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002283 }
2284 this->drawPaint(paint);
2285}
2286
reed@android.com845fdac2009-06-23 03:01:32 +00002287void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002288 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002289 SkPaint paint;
2290
2291 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002292 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002293 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002294 }
2295 this->drawPaint(paint);
2296}
2297
2298void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002299 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002300 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002301
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302 pt.set(x, y);
2303 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2304}
2305
2306void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002307 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308 SkPoint pt;
2309 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002310
reed@android.com8a1c16f2008-12-17 15:59:43 +00002311 pt.set(x, y);
2312 paint.setColor(color);
2313 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2314}
2315
2316void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2317 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002318 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002319 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002320
reed@android.com8a1c16f2008-12-17 15:59:43 +00002321 pts[0].set(x0, y0);
2322 pts[1].set(x1, y1);
2323 this->drawPoints(kLines_PointMode, 2, pts, paint);
2324}
2325
2326void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2327 SkScalar right, SkScalar bottom,
2328 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002329 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002330 SkRect r;
2331
2332 r.set(left, top, right, bottom);
2333 this->drawRect(r, paint);
2334}
2335
2336void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2337 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002338 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002339 if (radius < 0) {
2340 radius = 0;
2341 }
2342
2343 SkRect r;
2344 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002345 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002346}
2347
2348void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2349 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002350 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002351 if (rx > 0 && ry > 0) {
2352 if (paint.canComputeFastBounds()) {
2353 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002354 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002355 return;
2356 }
2357 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002358 SkRRect rrect;
2359 rrect.setRectXY(r, rx, ry);
2360 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002361 } else {
2362 this->drawRect(r, paint);
2363 }
2364}
2365
reed@android.com8a1c16f2008-12-17 15:59:43 +00002366void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2367 SkScalar sweepAngle, bool useCenter,
2368 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002369 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002370 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2371 this->drawOval(oval, paint);
2372 } else {
2373 SkPath path;
2374 if (useCenter) {
2375 path.moveTo(oval.centerX(), oval.centerY());
2376 }
2377 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2378 if (useCenter) {
2379 path.close();
2380 }
2381 this->drawPath(path, paint);
2382 }
2383}
2384
2385void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2386 const SkPath& path, SkScalar hOffset,
2387 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002388 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002389 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002390
reed@android.com8a1c16f2008-12-17 15:59:43 +00002391 matrix.setTranslate(hOffset, vOffset);
2392 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2393}
2394
reed@android.comf76bacf2009-05-13 14:00:33 +00002395///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002396void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002397 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002398 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002399 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002400 }
2401}
2402
reedd5fa1a42014-08-09 11:08:05 -07002403void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002404 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002405 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002406 if (matrix && matrix->isIdentity()) {
2407 matrix = NULL;
2408 }
2409 this->onDrawPicture(picture, matrix, paint);
2410 }
2411}
robertphillips9b14f262014-06-04 05:40:44 -07002412
reedd5fa1a42014-08-09 11:08:05 -07002413void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2414 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002415 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002416 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002417 // Canvas has to first give the device the opportunity to render
2418 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002419 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002420 return; // the device has rendered the entire picture
2421 }
2422 }
2423
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002424 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002425
robertphillipsc5ba71d2014-09-04 08:42:50 -07002426 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002427}
2428
reed@android.com8a1c16f2008-12-17 15:59:43 +00002429///////////////////////////////////////////////////////////////////////////////
2430///////////////////////////////////////////////////////////////////////////////
2431
2432SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002433 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002434
2435 SkASSERT(canvas);
2436
2437 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2438 fDone = !fImpl->next();
2439}
2440
2441SkCanvas::LayerIter::~LayerIter() {
2442 fImpl->~SkDrawIter();
2443}
2444
2445void SkCanvas::LayerIter::next() {
2446 fDone = !fImpl->next();
2447}
2448
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002449SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002450 return fImpl->getDevice();
2451}
2452
2453const SkMatrix& SkCanvas::LayerIter::matrix() const {
2454 return fImpl->getMatrix();
2455}
2456
2457const SkPaint& SkCanvas::LayerIter::paint() const {
2458 const SkPaint* paint = fImpl->getPaint();
2459 if (NULL == paint) {
2460 paint = &fDefaultPaint;
2461 }
2462 return *paint;
2463}
2464
2465const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2466int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2467int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002468
2469///////////////////////////////////////////////////////////////////////////////
2470
fmalitac3b589a2014-06-05 12:40:07 -07002471SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002472
2473///////////////////////////////////////////////////////////////////////////////
2474
2475static bool supported_for_raster_canvas(const SkImageInfo& info) {
2476 switch (info.alphaType()) {
2477 case kPremul_SkAlphaType:
2478 case kOpaque_SkAlphaType:
2479 break;
2480 default:
2481 return false;
2482 }
2483
2484 switch (info.colorType()) {
2485 case kAlpha_8_SkColorType:
2486 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002487 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002488 break;
2489 default:
2490 return false;
2491 }
2492
2493 return true;
2494}
2495
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002496SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2497 if (!supported_for_raster_canvas(info)) {
2498 return NULL;
2499 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002500
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002501 SkBitmap bitmap;
2502 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2503 return NULL;
2504 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002505 return SkNEW_ARGS(SkCanvas, (bitmap));
2506}
reedd5fa1a42014-08-09 11:08:05 -07002507
2508///////////////////////////////////////////////////////////////////////////////
2509
2510SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002511 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002512 : fCanvas(canvas)
2513 , fSaveCount(canvas->getSaveCount())
2514{
bsalomon49f085d2014-09-05 13:34:00 -07002515 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002516 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002517 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002518 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002519 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002520 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002521 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002522 canvas->save();
2523 }
mtklein6cfa73a2014-08-13 13:33:49 -07002524
bsalomon49f085d2014-09-05 13:34:00 -07002525 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002526 canvas->concat(*matrix);
2527 }
2528}
2529
2530SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2531 fCanvas->restoreToCount(fSaveCount);
2532}