blob: e4c03f3e5e0857464e52a43be2fa1518854d6e25 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
8#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -07009#include "SkCanvasPriv.h"
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000010#include "SkBitmapDevice.h"
senorblanco@chromium.org9c397442012-09-27 21:57:45 +000011#include "SkDeviceImageFilterProxy.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080013#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDrawFilter.h"
15#include "SkDrawLooper.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080016#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070017#include "SkImage.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000018#include "SkMetaData.h"
caryclark@google.com45a75fb2013-04-25 13:34:40 +000019#include "SkPathOps.h"
dandovb3c9d1c2014-08-12 08:34:29 -070020#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000021#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000022#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080023#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000024#include "SkRRect.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000025#include "SkSmallAllocator.h"
reed@google.com97af1a62012-08-28 12:19:02 +000026#include "SkSurface_Base.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000027#include "SkTemplates.h"
fmalita7ba7aa72014-08-29 09:46:36 -070028#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000029#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000030#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080031#include "SkTraceEvent.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000032#include "SkUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000033
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000034#if SK_SUPPORT_GPU
35#include "GrRenderTarget.h"
36#endif
37
reedd990e2f2014-12-22 11:58:30 -080038static bool gIgnoreSaveLayerBounds;
39void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
40 gIgnoreSaveLayerBounds = ignore;
41}
42bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
43 return gIgnoreSaveLayerBounds;
44}
45
reed0acf1b42014-12-22 16:12:38 -080046static bool gTreatSpriteAsBitmap;
47void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
48 gTreatSpriteAsBitmap = spriteAsBitmap;
49}
50bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
51 return gTreatSpriteAsBitmap;
52}
53
reed@google.comda17f752012-08-16 18:27:05 +000054// experimental for faster tiled drawing...
55//#define SK_ENABLE_CLIP_QUICKREJECT
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000056
reed@android.com8a1c16f2008-12-17 15:59:43 +000057//#define SK_TRACE_SAVERESTORE
58
59#ifdef SK_TRACE_SAVERESTORE
60 static int gLayerCounter;
61 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
62 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
63
64 static int gRecCounter;
65 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
66 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
67
68 static int gCanvasCounter;
69 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
70 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
71#else
72 #define inc_layer()
73 #define dec_layer()
74 #define inc_rec()
75 #define dec_rec()
76 #define inc_canvas()
77 #define dec_canvas()
78#endif
79
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +000080typedef SkTLazy<SkPaint> SkLazyPaint;
81
reed@google.com97af1a62012-08-28 12:19:02 +000082void SkCanvas::predrawNotify() {
83 if (fSurfaceBase) {
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +000084 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
reed@google.com97af1a62012-08-28 12:19:02 +000085 }
86}
87
reed@android.com8a1c16f2008-12-17 15:59:43 +000088///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000089
reed4a8126e2014-09-22 07:29:03 -070090static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
91 const uint32_t propFlags = props.flags();
92 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
93 flags &= ~SkPaint::kDither_Flag;
94 }
95 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
96 flags &= ~SkPaint::kAntiAlias_Flag;
97 }
98 return flags;
99}
100
101///////////////////////////////////////////////////////////////////////////////
102
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000103/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 The clip/matrix/proc are fields that reflect the top of the save/restore
105 stack. Whenever the canvas changes, it marks a dirty flag, and then before
106 these are used (assuming we're not on a layer) we rebuild these cache
107 values: they reflect the top of the save stack, but translated and clipped
108 by the device's XY offset and bitmap-bounds.
109*/
110struct DeviceCM {
111 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000112 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000113 SkRasterClip fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 const SkMatrix* fMatrix;
reed@google.com6f8f2922011-03-04 22:27:10 +0000115 SkPaint* fPaint; // may be null (in the future)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116
reed96e657d2015-03-10 17:30:07 -0700117 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reedd9544982014-09-09 18:46:22 -0700118 bool conservativeRasterClip)
119 : fNext(NULL)
120 , fClip(conservativeRasterClip)
121 {
122 if (NULL != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000124 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125 }
reed@google.com4b226022011-01-11 18:32:13 +0000126 fDevice = device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000128 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000130 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700131 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000132 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 fDevice->unref();
134 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000135 SkDELETE(fPaint);
136 }
reed@google.com4b226022011-01-11 18:32:13 +0000137
reed@google.com045e62d2011-10-24 12:19:46 +0000138 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
139 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000140 int x = fDevice->getOrigin().x();
141 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 int width = fDevice->width();
143 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000144
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 if ((x | y) == 0) {
146 fMatrix = &totalMatrix;
147 fClip = totalClip;
148 } else {
149 fMatrixStorage = totalMatrix;
150 fMatrixStorage.postTranslate(SkIntToScalar(-x),
151 SkIntToScalar(-y));
152 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000153
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 totalClip.translate(-x, -y, &fClip);
155 }
156
reed@google.com045e62d2011-10-24 12:19:46 +0000157 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158
159 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000160
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000162 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163 SkRegion::kDifference_Op);
164 }
reed@google.com4b226022011-01-11 18:32:13 +0000165
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000166 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
167
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168#ifdef SK_DEBUG
169 if (!fClip.isEmpty()) {
170 SkIRect deviceR;
171 deviceR.set(0, 0, width, height);
172 SkASSERT(deviceR.contains(fClip.getBounds()));
173 }
174#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000175 }
176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177private:
bsalomon@google.com0e354aa2012-10-08 20:44:25 +0000178 SkMatrix fMatrixStorage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179};
180
181/* This is the record we keep for each save/restore level in the stack.
182 Since a level optionally copies the matrix and/or stack, we have pointers
183 for these fields. If the value is copied for this level, the copy is
184 stored in the ...Storage field, and the pointer points to that. If the
185 value is not copied for this level, we ignore ...Storage, and just point
186 at the corresponding value in the previous level in the stack.
187*/
188class SkCanvas::MCRec {
189public:
reed1f836ee2014-07-07 07:49:34 -0700190 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700191 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 /* If there are any layers in the stack, this points to the top-most
193 one that is at or below this level in the stack (so we know what
194 bitmap/device to draw into from this level. This value is NOT
195 reference counted, since the real owner is either our fLayer field,
196 or a previous one in a lower level.)
197 */
reed2ff1fce2014-12-11 07:07:37 -0800198 DeviceCM* fTopLayer;
199 SkRasterClip fRasterClip;
200 SkMatrix fMatrix;
201 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202
reedd9544982014-09-09 18:46:22 -0700203 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
reedd9544982014-09-09 18:46:22 -0700204 fFilter = NULL;
205 fLayer = NULL;
206 fTopLayer = NULL;
reed2ff1fce2014-12-11 07:07:37 -0800207 fMatrix.reset();
208 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700209
reedd9544982014-09-09 18:46:22 -0700210 // don't bother initializing fNext
211 inc_rec();
212 }
reed2ff1fce2014-12-11 07:07:37 -0800213 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700214 fFilter = SkSafeRef(prev.fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215 fLayer = NULL;
reedd9544982014-09-09 18:46:22 -0700216 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800217 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700218
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 // don't bother initializing fNext
220 inc_rec();
221 }
222 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000223 SkSafeUnref(fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 SkDELETE(fLayer);
225 dec_rec();
226 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227};
228
229class SkDrawIter : public SkDraw {
230public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000231 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000232 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000233 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 canvas->updateDeviceCMCache();
235
joshualittde358a92015-02-05 08:19:35 -0800236 fClipStack = canvas->fClipStack.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000238 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 }
reed@google.com4b226022011-01-11 18:32:13 +0000240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 bool next() {
242 // skip over recs with empty clips
243 if (fSkipEmptyClips) {
244 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
245 fCurrLayer = fCurrLayer->fNext;
246 }
247 }
248
reed@google.comf68c5e22012-02-24 16:38:58 +0000249 const DeviceCM* rec = fCurrLayer;
250 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251
252 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000253 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
254 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 fDevice = rec->fDevice;
256 fBitmap = &fDevice->accessBitmap(true);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000258 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259
260 fCurrLayer = rec->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261 // fCurrLayer may be NULL now
reed@android.com199f1082009-06-10 02:12:47 +0000262
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 return true;
264 }
265 return false;
266 }
reed@google.com4b226022011-01-11 18:32:13 +0000267
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000268 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000269 int getX() const { return fDevice->getOrigin().x(); }
270 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 const SkMatrix& getMatrix() const { return *fMatrix; }
272 const SkRegion& getClip() const { return *fClip; }
273 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000274
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275private:
276 SkCanvas* fCanvas;
277 const DeviceCM* fCurrLayer;
278 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 SkBool8 fSkipEmptyClips;
280
281 typedef SkDraw INHERITED;
282};
283
284/////////////////////////////////////////////////////////////////////////////
285
286class AutoDrawLooper {
287public:
reed4a8126e2014-09-22 07:29:03 -0700288 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000289 bool skipLayerForImageFilter = false,
290 const SkRect* bounds = NULL) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000291 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700293 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000294 fSaveCount = canvas->getSaveCount();
reed@google.com8926b162012-03-23 15:36:36 +0000295 fDoClearImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000296 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297
reed1b110d62015-03-08 18:47:13 -0700298 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
reed@google.com8926b162012-03-23 15:36:36 +0000299 SkPaint tmp;
reed1b110d62015-03-08 18:47:13 -0700300 tmp.setImageFilter(fOrigPaint.getImageFilter());
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000301 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
302 true, SkCanvas::kFullLayer_SaveLayerStrategy);
reed@google.com8926b162012-03-23 15:36:36 +0000303 // we'll clear the imageFilter for the actual draws in next(), so
304 // it will only be applied during the restore().
305 fDoClearImageFilter = true;
306 }
307
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000308 if (SkDrawLooper* looper = paint.getLooper()) {
309 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
310 looper->contextSize());
311 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000312 fIsSimple = false;
313 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000314 fLooperContext = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000315 // can we be marked as simple?
316 fIsSimple = !fFilter && !fDoClearImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000317 }
piotaixrb5fae932014-09-24 13:03:30 -0700318
reed4a8126e2014-09-22 07:29:03 -0700319 uint32_t oldFlags = paint.getFlags();
320 fNewPaintFlags = filter_paint_flags(props, oldFlags);
321 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reed1b110d62015-03-08 18:47:13 -0700322 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700323 paint->setFlags(fNewPaintFlags);
324 fPaint = paint;
325 // if we're not simple, doNext() will take care of calling setFlags()
326 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000327 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000328
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 ~AutoDrawLooper() {
reed@google.com8926b162012-03-23 15:36:36 +0000330 if (fDoClearImageFilter) {
331 fCanvas->internalRestore();
332 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000333 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000335
reed@google.com4e2b3d32011-04-07 14:18:59 +0000336 const SkPaint& paint() const {
337 SkASSERT(fPaint);
338 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000340
reed@google.com129ec222012-05-15 13:24:09 +0000341 bool next(SkDrawFilter::Type drawType) {
342 if (fDone) {
343 return false;
344 } else if (fIsSimple) {
345 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000346 return !fPaint->nothingToDraw();
347 } else {
348 return this->doNext(drawType);
349 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000350 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000351
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352private:
reed1b110d62015-03-08 18:47:13 -0700353 SkLazyPaint fLazyPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000354 SkCanvas* fCanvas;
355 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000356 SkDrawFilter* fFilter;
357 const SkPaint* fPaint;
358 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700359 uint32_t fNewPaintFlags;
reed@google.com8926b162012-03-23 15:36:36 +0000360 bool fDoClearImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000361 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000362 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000363 SkDrawLooper::Context* fLooperContext;
364 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000365
366 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367};
368
reed@google.com129ec222012-05-15 13:24:09 +0000369bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
reed@google.com632e1a22011-10-06 12:37:00 +0000370 fPaint = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000371 SkASSERT(!fIsSimple);
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000372 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000373
reed1b110d62015-03-08 18:47:13 -0700374 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700375 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000376
377 if (fDoClearImageFilter) {
378 paint->setImageFilter(NULL);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000379 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000380
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000381 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000382 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000383 return false;
384 }
385 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000386 if (!fFilter->filter(paint, drawType)) {
387 fDone = true;
388 return false;
389 }
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000390 if (NULL == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000391 // no looper means we only draw once
392 fDone = true;
393 }
394 }
395 fPaint = paint;
396
397 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000398 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000399 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000400 }
401
402 // call this after any possible paint modifiers
403 if (fPaint->nothingToDraw()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000404 fPaint = NULL;
405 return false;
406 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000407 return true;
408}
409
reed@android.com8a1c16f2008-12-17 15:59:43 +0000410////////// macros to place around the internal draw calls //////////////////
411
reed@google.com8926b162012-03-23 15:36:36 +0000412#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000413 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700414 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000415 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000416 SkDrawIter iter(this);
417
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000418#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000419 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700420 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000421 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000423
reed@google.com4e2b3d32011-04-07 14:18:59 +0000424#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000425
426////////////////////////////////////////////////////////////////////////////
427
reedd9544982014-09-09 18:46:22 -0700428SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
429 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
reed@google.comc0784db2013-12-13 21:16:12 +0000430 fCachedLocalClipBounds.setEmpty();
431 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000432 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000433 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700434 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800435 fSaveCount = 1;
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000436 fMetaData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437
438 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700439 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440
reed96e657d2015-03-10 17:30:07 -0700441 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, NULL, NULL, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443
reed@google.com97af1a62012-08-28 12:19:02 +0000444 fSurfaceBase = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000445
joshualittde358a92015-02-05 08:19:35 -0800446 fClipStack.reset(SkNEW(SkClipStack));
447
reedf92c8662014-08-18 08:02:43 -0700448 if (device) {
reedb2db8982014-11-13 12:41:02 -0800449 device->initForRootLayer(fProps.pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700450 if (device->forceConservativeRasterClip()) {
451 fConservativeRasterClip = true;
452 }
reedf92c8662014-08-18 08:02:43 -0700453 device->onAttachToCanvas(this);
454 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800455 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700456 }
457 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000458}
459
reed@google.comcde92112011-07-06 20:00:52 +0000460SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000461 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700462 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000463{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000464 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000465
reedd9544982014-09-09 18:46:22 -0700466 this->init(NULL, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000467}
468
reedd9544982014-09-09 18:46:22 -0700469static SkBitmap make_nopixels(int width, int height) {
470 SkBitmap bitmap;
471 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
472 return bitmap;
473}
474
475class SkNoPixelsBitmapDevice : public SkBitmapDevice {
476public:
reed78e27682014-11-19 08:04:34 -0800477 SkNoPixelsBitmapDevice(const SkIRect& bounds)
478 : INHERITED(make_nopixels(bounds.width(), bounds.height()))
479 {
480 this->setOrigin(bounds.x(), bounds.y());
481 }
reedd9544982014-09-09 18:46:22 -0700482
483private:
piotaixrb5fae932014-09-24 13:03:30 -0700484
reedd9544982014-09-09 18:46:22 -0700485 typedef SkBitmapDevice INHERITED;
486};
487
reed96a857e2015-01-25 10:33:58 -0800488SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000489 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800490 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000491{
492 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700493
reed78e27682014-11-19 08:04:34 -0800494 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
495 (SkIRect::MakeWH(width, height))), kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700496}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000497
reed78e27682014-11-19 08:04:34 -0800498SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700499 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700500 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700501{
502 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700503
reed78e27682014-11-19 08:04:34 -0800504 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds)), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700505}
506
reed4a8126e2014-09-22 07:29:03 -0700507SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700508 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700509 , fProps(SkSurfacePropsCopyOrDefault(props))
reedd9544982014-09-09 18:46:22 -0700510{
511 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700512
reedd9544982014-09-09 18:46:22 -0700513 this->init(device, flags);
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000514}
515
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000516SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000517 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700518 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000519{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000520 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700521
reedd9544982014-09-09 18:46:22 -0700522 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523}
524
reed4a8126e2014-09-22 07:29:03 -0700525SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700526 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700527 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700528{
529 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700530
reed4a8126e2014-09-22 07:29:03 -0700531 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
532 this->init(device, kDefault_InitFlags);
533}
reed29c857d2014-09-21 10:25:07 -0700534
reed4a8126e2014-09-22 07:29:03 -0700535SkCanvas::SkCanvas(const SkBitmap& bitmap)
536 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
537 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
538{
539 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700540
reed4a8126e2014-09-22 07:29:03 -0700541 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
542 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000543}
544
545SkCanvas::~SkCanvas() {
546 // free up the contents of our deque
547 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000548
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549 this->internalRestore(); // restore the last, since we're going away
550
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000551 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000552
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553 dec_canvas();
554}
555
reed@android.com8a1c16f2008-12-17 15:59:43 +0000556SkDrawFilter* SkCanvas::getDrawFilter() const {
557 return fMCRec->fFilter;
558}
559
560SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
561 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
562 return filter;
563}
564
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000565SkMetaData& SkCanvas::getMetaData() {
566 // metadata users are rare, so we lazily allocate it. If that changes we
567 // can decide to just make it a field in the device (rather than a ptr)
568 if (NULL == fMetaData) {
569 fMetaData = new SkMetaData;
570 }
571 return *fMetaData;
572}
573
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574///////////////////////////////////////////////////////////////////////////////
575
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000576void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000577 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000578 if (device) {
579 device->flush();
580 }
581}
582
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000583SkISize SkCanvas::getTopLayerSize() const {
584 SkBaseDevice* d = this->getTopDevice();
585 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
586}
587
588SkIPoint SkCanvas::getTopLayerOrigin() const {
589 SkBaseDevice* d = this->getTopDevice();
590 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
591}
592
593SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000594 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000595 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
596}
597
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000598SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000599 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000600 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601 SkASSERT(rec && rec->fLayer);
602 return rec->fLayer->fDevice;
603}
604
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000605SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000606 if (updateMatrixClip) {
607 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
608 }
reed@google.com9266fed2011-03-30 00:18:03 +0000609 return fMCRec->fTopLayer->fDevice;
610}
611
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000612bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
613 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
614 return false;
615 }
616
617 bool weAllocated = false;
618 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700619 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000620 return false;
621 }
622 weAllocated = true;
623 }
624
625 SkBitmap bm(*bitmap);
626 bm.lockPixels();
627 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
628 return true;
629 }
630
631 if (weAllocated) {
632 bitmap->setPixelRef(NULL);
633 }
634 return false;
635}
reed@google.com51df9e32010-12-23 19:29:18 +0000636
bsalomon@google.comc6980972011-11-02 19:57:21 +0000637bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000638 SkIRect r = srcRect;
639 const SkISize size = this->getBaseLayerSize();
640 if (!r.intersect(0, 0, size.width(), size.height())) {
641 bitmap->reset();
642 return false;
643 }
644
reed84825042014-09-02 12:50:45 -0700645 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000646 // bitmap will already be reset.
647 return false;
648 }
649 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
650 bitmap->reset();
651 return false;
652 }
653 return true;
654}
655
reed96472de2014-12-10 09:53:42 -0800656bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000657 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000658 if (!device) {
659 return false;
660 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000661 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800662
reed96472de2014-12-10 09:53:42 -0800663 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
664 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000665 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000666 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000667
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000668 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800669 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000670}
671
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000672bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
673 if (bitmap.getTexture()) {
674 return false;
675 }
676 SkBitmap bm(bitmap);
677 bm.lockPixels();
678 if (bm.getPixels()) {
679 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
680 }
681 return false;
682}
683
684bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
685 int x, int y) {
686 switch (origInfo.colorType()) {
687 case kUnknown_SkColorType:
688 case kIndex_8_SkColorType:
689 return false;
690 default:
691 break;
692 }
693 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
694 return false;
695 }
696
697 const SkISize size = this->getBaseLayerSize();
698 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
699 if (!target.intersect(0, 0, size.width(), size.height())) {
700 return false;
701 }
702
703 SkBaseDevice* device = this->getDevice();
704 if (!device) {
705 return false;
706 }
707
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000708 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700709 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000710
711 // if x or y are negative, then we have to adjust pixels
712 if (x > 0) {
713 x = 0;
714 }
715 if (y > 0) {
716 y = 0;
717 }
718 // here x,y are either 0 or negative
719 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
720
reed4af35f32014-06-27 17:47:49 -0700721 // Tell our owning surface to bump its generation ID
722 this->predrawNotify();
723
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000724 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000725 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000726}
reed@google.com51df9e32010-12-23 19:29:18 +0000727
junov@google.com4370aed2012-01-18 16:21:08 +0000728SkCanvas* SkCanvas::canvasForDrawIter() {
729 return this;
730}
731
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732//////////////////////////////////////////////////////////////////////////////
733
reed@android.com8a1c16f2008-12-17 15:59:43 +0000734void SkCanvas::updateDeviceCMCache() {
735 if (fDeviceCMDirty) {
736 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700737 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000739
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740 if (NULL == layer->fNext) { // only one layer
joshualittde358a92015-02-05 08:19:35 -0800741 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000743 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000744 do {
joshualittde358a92015-02-05 08:19:35 -0800745 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746 } while ((layer = layer->fNext) != NULL);
747 }
748 fDeviceCMDirty = false;
749 }
750}
751
reed@android.com8a1c16f2008-12-17 15:59:43 +0000752///////////////////////////////////////////////////////////////////////////////
753
reed2ff1fce2014-12-11 07:07:37 -0800754void SkCanvas::checkForDeferredSave() {
755 if (fMCRec->fDeferredSaveCount > 0) {
756 fMCRec->fDeferredSaveCount -= 1;
757 this->doSave();
758 }
759}
760
reedf0090cb2014-11-26 08:55:51 -0800761int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800762#ifdef SK_DEBUG
763 int count = 0;
764 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
765 for (;;) {
766 const MCRec* rec = (const MCRec*)iter.next();
767 if (!rec) {
768 break;
769 }
770 count += 1 + rec->fDeferredSaveCount;
771 }
772 SkASSERT(count == fSaveCount);
773#endif
774 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800775}
776
777int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800778 fSaveCount += 1;
779 fMCRec->fDeferredSaveCount += 1;
780 return this->getSaveCount() - 1; // return our prev value
781}
782
783void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800784 this->willSave();
reed2ff1fce2014-12-11 07:07:37 -0800785 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800786}
787
788void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800789 if (fMCRec->fDeferredSaveCount > 0) {
790 SkASSERT(fSaveCount > 1);
791 fSaveCount -= 1;
792 fMCRec->fDeferredSaveCount -= 1;
793 } else {
794 // check for underflow
795 if (fMCStack.count() > 1) {
796 this->willRestore();
797 SkASSERT(fSaveCount > 1);
798 fSaveCount -= 1;
799 this->internalRestore();
800 this->didRestore();
801 }
reedf0090cb2014-11-26 08:55:51 -0800802 }
803}
804
805void SkCanvas::restoreToCount(int count) {
806 // sanity check
807 if (count < 1) {
808 count = 1;
809 }
mtkleinf0f14112014-12-12 08:46:25 -0800810
reedf0090cb2014-11-26 08:55:51 -0800811 int n = this->getSaveCount() - count;
812 for (int i = 0; i < n; ++i) {
813 this->restore();
814 }
815}
816
reed2ff1fce2014-12-11 07:07:37 -0800817void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000818 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700819 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000820 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000821
joshualittde358a92015-02-05 08:19:35 -0800822 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823}
824
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000826#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000828#else
829 return true;
830#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831}
832
junov@chromium.orga907ac32012-02-24 21:54:07 +0000833bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
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
reed96e657d2015-03-10 17:30:07 -0700841 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
842
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000843 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700844 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000845 // Filters may grow the bounds beyond the device bounds.
846 op = SkRegion::kReplace_Op;
847 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000848 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700849 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000851
reed96e657d2015-03-10 17:30:07 -0700852 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000853 r.roundOut(&ir);
854 // early exit if the layer's bounds are clipped out
855 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000856 if (bounds_affects_clip(flags)) {
reed1f836ee2014-07-07 07:49:34 -0700857 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000858 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000859 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000860 }
861 } else { // no user bounds, so just use the clip
862 ir = clipBounds;
863 }
864
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000865 if (bounds_affects_clip(flags)) {
joshualittde358a92015-02-05 08:19:35 -0800866 fClipStack->clipDevRect(ir, op);
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000867 // early exit if the clip is now empty
reed1f836ee2014-07-07 07:49:34 -0700868 if (!fMCRec->fRasterClip.op(ir, op)) {
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000869 return false;
870 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000871 }
872
873 if (intersection) {
874 *intersection = ir;
875 }
876 return true;
877}
878
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000879int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800880 if (gIgnoreSaveLayerBounds) {
881 bounds = NULL;
882 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000883 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reed2ff1fce2014-12-11 07:07:37 -0800884 fSaveCount += 1;
885 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy);
886 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000887}
888
reed2ff1fce2014-12-11 07:07:37 -0800889int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800890 if (gIgnoreSaveLayerBounds) {
891 bounds = NULL;
892 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000893 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reed2ff1fce2014-12-11 07:07:37 -0800894 fSaveCount += 1;
895 this->internalSaveLayer(bounds, paint, flags, false, strategy);
896 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000897}
898
reed2ff1fce2014-12-11 07:07:37 -0800899void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000900 bool justForImageFilter, SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000901#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000902 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000903#endif
904
junov@chromium.orga907ac32012-02-24 21:54:07 +0000905 // do this before we create the layer. We don't call the public save() since
906 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -0800907 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000908
909 fDeviceCMDirty = true;
910
911 SkIRect ir;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000912 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -0800913 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000914 }
915
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000916 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
917 // the clipRectBounds() call above?
918 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -0800919 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000920 }
921
reed@google.comb55deeb2012-01-06 14:43:09 +0000922 // Kill the imagefilter if our device doesn't allow it
923 SkLazyPaint lazyP;
924 if (paint && paint->getImageFilter()) {
925 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
reed@google.com8926b162012-03-23 15:36:36 +0000926 if (justForImageFilter) {
927 // early exit if the layer was just for the imageFilter
reed2ff1fce2014-12-11 07:07:37 -0800928 return;
reed@google.com8926b162012-03-23 15:36:36 +0000929 }
reed@google.comb55deeb2012-01-06 14:43:09 +0000930 SkPaint* p = lazyP.set(*paint);
931 p->setImageFilter(NULL);
932 paint = p;
933 }
934 }
935
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000936 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
937 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
938 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000939
reedb2db8982014-11-13 12:41:02 -0800940 SkBaseDevice* device = this->getTopDevice();
941 if (NULL == device) {
942 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800943 return;
reed@google.com76dd2772012-01-05 21:15:07 +0000944 }
reedb2db8982014-11-13 12:41:02 -0800945
946 SkBaseDevice::Usage usage = SkBaseDevice::kSaveLayer_Usage;
947 if (paint && paint->getImageFilter()) {
948 usage = SkBaseDevice::kImageFilter_Usage;
949 }
950 device = device->onCreateCompatibleDevice(SkBaseDevice::CreateInfo(info, usage,
951 fProps.pixelGeometry()));
bungeman@google.come25c6842011-08-17 14:53:54 +0000952 if (NULL == device) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800953 SkErrorInternals::SetError( kInternalError_SkError,
954 "Unable to create device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800955 return;
bungeman@google.come25c6842011-08-17 14:53:54 +0000956 }
bsalomon@google.come97f0852011-06-17 13:10:25 +0000957
reed@google.com6f8f2922011-03-04 22:27:10 +0000958 device->setOrigin(ir.fLeft, ir.fTop);
reed96e657d2015-03-10 17:30:07 -0700959 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960 device->unref();
961
962 layer->fNext = fMCRec->fTopLayer;
963 fMCRec->fLayer = layer;
964 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965}
966
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000967int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
968 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
969}
970
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
972 SaveFlags flags) {
973 if (0xFF == alpha) {
974 return this->saveLayer(bounds, NULL, flags);
975 } else {
976 SkPaint tmpPaint;
977 tmpPaint.setAlpha(alpha);
978 return this->saveLayer(bounds, &tmpPaint, flags);
979 }
980}
981
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982void SkCanvas::internalRestore() {
983 SkASSERT(fMCStack.count() != 0);
984
985 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +0000986 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987
joshualittde358a92015-02-05 08:19:35 -0800988 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +0000989
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000990 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000991 DeviceCM* layer = fMCRec->fLayer; // may be null
992 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
993 fMCRec->fLayer = NULL;
994
995 // now do the normal restore()
996 fMCRec->~MCRec(); // balanced in save()
997 fMCStack.pop_back();
998 fMCRec = (MCRec*)fMCStack.back();
999
1000 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1001 since if we're being recorded, we don't want to record this (the
1002 recorder will have already recorded the restore).
1003 */
bsalomon49f085d2014-09-05 13:34:00 -07001004 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001005 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001006 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001007 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1008 layer->fPaint);
1009 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001010 fDeviceCMDirty = true;
1011 }
1012 SkDELETE(layer);
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001013 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001014}
1015
reed4a8126e2014-09-22 07:29:03 -07001016SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1017 if (NULL == props) {
1018 props = &fProps;
1019 }
1020 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001021}
1022
reed4a8126e2014-09-22 07:29:03 -07001023SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001024 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001025 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001026}
1027
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001028SkImageInfo SkCanvas::imageInfo() const {
1029 SkBaseDevice* dev = this->getDevice();
1030 if (dev) {
1031 return dev->imageInfo();
1032 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001033 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001034 }
1035}
1036
1037const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1038 return this->onPeekPixels(info, rowBytes);
1039}
1040
1041const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1042 SkBaseDevice* dev = this->getDevice();
1043 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1044}
1045
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001046void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1047 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1048 if (pixels && origin) {
1049 *origin = this->getTopDevice(false)->getOrigin();
1050 }
1051 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001052}
1053
1054void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1055 SkBaseDevice* dev = this->getTopDevice();
1056 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1057}
1058
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001059SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1060 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1061 if (NULL == fAddr) {
1062 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001063 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001064 return; // failure, fAddr is NULL
1065 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001066 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1067 return; // failure, fAddr is NULL
1068 }
1069 fAddr = fBitmap.getPixels();
1070 fRowBytes = fBitmap.rowBytes();
1071 }
1072 SkASSERT(fAddr); // success
1073}
1074
1075bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1076 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001077 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001078 } else {
1079 bitmap->reset();
1080 return false;
1081 }
1082}
1083
reed@android.com8a1c16f2008-12-17 15:59:43 +00001084/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001085void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001087 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088 return;
1089 }
1090
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001091 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001092 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001093 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001094 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001095
1096 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001097
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001098 SkRect storage;
1099 const SkRect* bounds = NULL;
1100 if (paint && paint->canComputeFastBounds()) {
1101 bitmap.getBounds(&storage);
1102 matrix.mapRect(&storage);
1103 bounds = &paint->computeFastBounds(storage, &storage);
1104 }
1105
1106 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001107
1108 while (iter.next()) {
1109 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1110 }
1111
1112 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001113}
1114
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001115void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed@google.com8926b162012-03-23 15:36:36 +00001116 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001117 SkPaint tmp;
1118 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001119 paint = &tmp;
1120 }
reed@google.com4b226022011-01-11 18:32:13 +00001121
reed@google.com8926b162012-03-23 15:36:36 +00001122 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001123 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001124 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001125 paint = &looper.paint();
1126 SkImageFilter* filter = paint->getImageFilter();
1127 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001128 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001129 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001130 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001131 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001132 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001133 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001134 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001135 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001136 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001137 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001138 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001139 SkPaint tmpUnfiltered(*paint);
1140 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001141 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1142 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001143 }
1144 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001145 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001146 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001148 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149}
1150
reed41af9662015-01-05 07:49:08 -08001151void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001152 if (gTreatSpriteAsBitmap) {
1153 this->save();
1154 this->resetMatrix();
1155 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1156 this->restore();
1157 return;
1158 }
1159
danakj9881d632014-11-26 12:41:06 -08001160 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001161 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001162 return;
1163 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001164 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001165
reed@google.com8926b162012-03-23 15:36:36 +00001166 SkPaint tmp;
1167 if (NULL == paint) {
1168 paint = &tmp;
1169 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001170
reed@google.com8926b162012-03-23 15:36:36 +00001171 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001172
reed@google.com8926b162012-03-23 15:36:36 +00001173 while (iter.next()) {
1174 paint = &looper.paint();
1175 SkImageFilter* filter = paint->getImageFilter();
1176 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1177 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001178 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001179 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001180 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001181 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001182 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001183 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001184 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001185 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001186 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001187 SkPaint tmpUnfiltered(*paint);
1188 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001189 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001190 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001191 }
1192 } else {
1193 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1194 }
1195 }
1196 LOOPER_END
1197}
1198
reed@android.com8a1c16f2008-12-17 15:59:43 +00001199/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001200void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001201 SkMatrix m;
1202 m.setTranslate(dx, dy);
1203 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001204}
1205
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001206void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001207 SkMatrix m;
1208 m.setScale(sx, sy);
1209 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001210}
1211
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001212void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001213 SkMatrix m;
1214 m.setRotate(degrees);
1215 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216}
1217
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001218void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001219 SkMatrix m;
1220 m.setSkew(sx, sy);
1221 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001222}
1223
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001224void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001225 if (matrix.isIdentity()) {
1226 return;
1227 }
1228
reed2ff1fce2014-12-11 07:07:37 -08001229 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001231 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001232 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001233
1234 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001235}
1236
reed@android.com8a1c16f2008-12-17 15:59:43 +00001237void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001238 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001240 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001241 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001242 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001243}
1244
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245void SkCanvas::resetMatrix() {
1246 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001247
reed@android.com8a1c16f2008-12-17 15:59:43 +00001248 matrix.reset();
1249 this->setMatrix(matrix);
1250}
1251
1252//////////////////////////////////////////////////////////////////////////////
1253
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001254void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001255 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001256 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1257 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001258}
1259
1260void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001261#ifdef SK_ENABLE_CLIP_QUICKREJECT
1262 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001263 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001264 return false;
1265 }
1266
reed@google.com3b3e8952012-08-16 20:53:31 +00001267 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001268 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001269 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001270
1271 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001272 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001273 }
1274 }
1275#endif
1276
reed@google.com5c3d1472011-02-22 19:12:23 +00001277 AutoValidateClip avc(this);
1278
reed@android.com8a1c16f2008-12-17 15:59:43 +00001279 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001280 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001281 if (!fAllowSoftClip) {
1282 edgeStyle = kHard_ClipEdgeStyle;
1283 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001284
reed1f836ee2014-07-07 07:49:34 -07001285 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001286 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001287 // the matrix. This means we don't have to a) make a path, and b) tell
1288 // the region code to scan-convert the path, only to discover that it
1289 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001291
reed1f836ee2014-07-07 07:49:34 -07001292 fMCRec->fMatrix.mapRect(&r, rect);
joshualittde358a92015-02-05 08:19:35 -08001293 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001294 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001296 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001297 // and clip against that, since it can handle any matrix. However, to
1298 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1299 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300 SkPath path;
1301
1302 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001303 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001304 }
1305}
1306
reed73e714e2014-09-04 09:02:23 -07001307static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1308 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001309 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001310}
1311
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001312void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001313 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001314 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001315 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001316 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1317 } else {
1318 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001319 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001320}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001321
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001322void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001323 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001324 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001325 AutoValidateClip avc(this);
1326
1327 fDeviceCMDirty = true;
1328 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001329 if (!fAllowSoftClip) {
1330 edgeStyle = kHard_ClipEdgeStyle;
1331 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001332
joshualittde358a92015-02-05 08:19:35 -08001333 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001334
1335 SkPath devPath;
1336 devPath.addRRect(transformedRRect);
1337
reed73e714e2014-09-04 09:02:23 -07001338 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001339 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001340 }
1341
1342 SkPath path;
1343 path.addRRect(rrect);
1344 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001345 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001346}
1347
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001348void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001349 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001350 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1351 SkRect r;
1352 if (!path.isInverseFillType() && path.isRect(&r)) {
1353 this->onClipRect(r, op, edgeStyle);
1354 } else {
1355 this->onClipPath(path, op, edgeStyle);
1356 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001357}
1358
1359void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001360#ifdef SK_ENABLE_CLIP_QUICKREJECT
1361 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001362 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001363 return false;
1364 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001365
reed@google.com3b3e8952012-08-16 20:53:31 +00001366 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001367 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001368 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001369
reed@google.comda17f752012-08-16 18:27:05 +00001370 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001371 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001372 }
1373 }
1374#endif
1375
reed@google.com5c3d1472011-02-22 19:12:23 +00001376 AutoValidateClip avc(this);
1377
reed@android.com8a1c16f2008-12-17 15:59:43 +00001378 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001379 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001380 if (!fAllowSoftClip) {
1381 edgeStyle = kHard_ClipEdgeStyle;
1382 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001383
1384 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001385 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001386
reed@google.comfe701122011-11-08 19:41:23 +00001387 // Check if the transfomation, or the original path itself
1388 // made us empty. Note this can also happen if we contained NaN
1389 // values. computing the bounds detects this, and will set our
1390 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1391 if (devPath.getBounds().isEmpty()) {
1392 // resetting the path will remove any NaN or other wanky values
1393 // that might upset our scan converter.
1394 devPath.reset();
1395 }
1396
reed@google.com5c3d1472011-02-22 19:12:23 +00001397 // if we called path.swap() we could avoid a deep copy of this path
joshualittde358a92015-02-05 08:19:35 -08001398 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001399
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001400 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001401 bool clipIsAA = getClipStack()->asPath(&devPath);
1402 if (clipIsAA) {
1403 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001404 }
fmalita1a481fe2015-02-04 07:39:34 -08001405
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001406 op = SkRegion::kReplace_Op;
1407 }
1408
reed73e714e2014-09-04 09:02:23 -07001409 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001410}
1411
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001412void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001413 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001414 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001415}
1416
1417void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001418 AutoValidateClip avc(this);
1419
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001421 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422
reed@google.com5c3d1472011-02-22 19:12:23 +00001423 // todo: signal fClipStack that we have a region, and therefore (I guess)
1424 // we have to ignore it, and use the region directly?
joshualittde358a92015-02-05 08:19:35 -08001425 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001426
reed1f836ee2014-07-07 07:49:34 -07001427 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428}
1429
reed@google.com819c9212011-02-23 18:56:55 +00001430#ifdef SK_DEBUG
1431void SkCanvas::validateClip() const {
1432 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001433 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001434 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001435 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001436 return;
1437 }
1438
reed@google.com819c9212011-02-23 18:56:55 +00001439 SkIRect ir;
1440 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001441 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001442
joshualittde358a92015-02-05 08:19:35 -08001443 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001444 const SkClipStack::Element* element;
1445 while ((element = iter.next()) != NULL) {
1446 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001447 case SkClipStack::Element::kRect_Type:
1448 element->getRect().round(&ir);
1449 tmpClip.op(ir, element->getOp());
1450 break;
1451 case SkClipStack::Element::kEmpty_Type:
1452 tmpClip.setEmpty();
1453 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001454 default: {
1455 SkPath path;
1456 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001457 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001458 break;
1459 }
reed@google.com819c9212011-02-23 18:56:55 +00001460 }
1461 }
reed@google.com819c9212011-02-23 18:56:55 +00001462}
1463#endif
1464
reed@google.com90c07ea2012-04-13 13:50:27 +00001465void SkCanvas::replayClips(ClipVisitor* visitor) const {
joshualittde358a92015-02-05 08:19:35 -08001466 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001467 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001468
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001469 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001470 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001471 }
1472}
1473
reed@google.com5c3d1472011-02-22 19:12:23 +00001474///////////////////////////////////////////////////////////////////////////////
1475
reed@google.com754de5f2014-02-24 19:38:20 +00001476bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001477 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001478}
1479
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001480bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001481 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001482}
1483
reed@google.com3b3e8952012-08-16 20:53:31 +00001484bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001485 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001486 return true;
1487
reed1f836ee2014-07-07 07:49:34 -07001488 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001489 return true;
1490 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001491
reed1f836ee2014-07-07 07:49:34 -07001492 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001493 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001494 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001495 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001496 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001497 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001498
reed@android.coma380ae42009-07-21 01:17:02 +00001499 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001500 // TODO: should we use | instead, or compare all 4 at once?
1501 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001502 return true;
1503 }
reed@google.comc0784db2013-12-13 21:16:12 +00001504 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001505 return true;
1506 }
1507 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001509}
1510
reed@google.com3b3e8952012-08-16 20:53:31 +00001511bool SkCanvas::quickReject(const SkPath& path) const {
1512 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001513}
1514
reed@google.com3b3e8952012-08-16 20:53:31 +00001515bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001516 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001517 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001518 return false;
1519 }
1520
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001521 SkMatrix inverse;
1522 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001523 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001524 if (bounds) {
1525 bounds->setEmpty();
1526 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001527 return false;
1528 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001529
bsalomon49f085d2014-09-05 13:34:00 -07001530 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001531 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001532 // adjust it outwards in case we are antialiasing
1533 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001534
reed@google.com8f4d2302013-12-17 16:44:46 +00001535 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1536 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001537 inverse.mapRect(bounds, r);
1538 }
1539 return true;
1540}
1541
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001542bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001543 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001544 if (clip.isEmpty()) {
1545 if (bounds) {
1546 bounds->setEmpty();
1547 }
1548 return false;
1549 }
1550
bsalomon49f085d2014-09-05 13:34:00 -07001551 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001552 *bounds = clip.getBounds();
1553 }
1554 return true;
1555}
1556
reed@android.com8a1c16f2008-12-17 15:59:43 +00001557const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001558 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001559}
1560
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001561const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001562 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001563}
1564
reed@google.com9c135db2014-03-12 18:28:35 +00001565GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1566 SkBaseDevice* dev = this->getTopDevice();
1567 return dev ? dev->accessRenderTarget() : NULL;
1568}
1569
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001570GrContext* SkCanvas::getGrContext() {
1571#if SK_SUPPORT_GPU
1572 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001573 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001574 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001575 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001576 return renderTarget->getContext();
1577 }
1578 }
1579#endif
1580
1581 return NULL;
1582
1583}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001584
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001585void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1586 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001587 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001588 if (outer.isEmpty()) {
1589 return;
1590 }
1591 if (inner.isEmpty()) {
1592 this->drawRRect(outer, paint);
1593 return;
1594 }
1595
1596 // We don't have this method (yet), but technically this is what we should
1597 // be able to assert...
1598 // SkASSERT(outer.contains(inner));
1599 //
1600 // For now at least check for containment of bounds
1601 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1602
1603 this->onDrawDRRect(outer, inner, paint);
1604}
1605
reed41af9662015-01-05 07:49:08 -08001606// These need to stop being virtual -- clients need to override the onDraw... versions
1607
1608void SkCanvas::drawPaint(const SkPaint& paint) {
1609 this->onDrawPaint(paint);
1610}
1611
1612void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1613 this->onDrawRect(r, paint);
1614}
1615
1616void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1617 this->onDrawOval(r, paint);
1618}
1619
1620void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1621 this->onDrawRRect(rrect, paint);
1622}
1623
1624void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1625 this->onDrawPoints(mode, count, pts, paint);
1626}
1627
1628void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1629 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1630 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1631 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1632 indices, indexCount, paint);
1633}
1634
1635void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1636 this->onDrawPath(path, paint);
1637}
1638
1639void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1640 this->onDrawImage(image, dx, dy, paint);
1641}
1642
1643void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1644 const SkPaint* paint) {
1645 this->onDrawImageRect(image, src, dst, paint);
1646}
1647
1648void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1649 this->onDrawBitmap(bitmap, dx, dy, paint);
1650}
1651
1652void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1653 const SkPaint* paint, DrawBitmapRectFlags flags) {
1654 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1655}
1656
1657void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1658 const SkPaint* paint) {
1659 this->onDrawBitmapNine(bitmap, center, dst, paint);
1660}
1661
1662void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
1663 this->onDrawSprite(bitmap, left, top, paint);
1664}
1665
reed@android.com8a1c16f2008-12-17 15:59:43 +00001666//////////////////////////////////////////////////////////////////////////////
1667// These are the virtual drawing methods
1668//////////////////////////////////////////////////////////////////////////////
1669
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001670void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001671 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001672 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1673 }
1674}
1675
reed41af9662015-01-05 07:49:08 -08001676void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001677 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001678 this->internalDrawPaint(paint);
1679}
1680
1681void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001682 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001683
1684 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001685 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001686 }
1687
reed@google.com4e2b3d32011-04-07 14:18:59 +00001688 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001689}
1690
reed41af9662015-01-05 07:49:08 -08001691void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1692 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001693 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001694 if ((long)count <= 0) {
1695 return;
1696 }
1697
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001698 SkRect r, storage;
1699 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001700 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001701 // special-case 2 points (common for drawing a single line)
1702 if (2 == count) {
1703 r.set(pts[0], pts[1]);
1704 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001705 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001706 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001707 bounds = &paint.computeFastStrokeBounds(r, &storage);
1708 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001709 return;
1710 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001711 }
reed@google.coma584aed2012-05-16 14:06:02 +00001712
reed@android.com8a1c16f2008-12-17 15:59:43 +00001713 SkASSERT(pts != NULL);
1714
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001715 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001716
reed@android.com8a1c16f2008-12-17 15:59:43 +00001717 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001718 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001719 }
reed@google.com4b226022011-01-11 18:32:13 +00001720
reed@google.com4e2b3d32011-04-07 14:18:59 +00001721 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001722}
1723
reed41af9662015-01-05 07:49:08 -08001724void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001725 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001726 SkRect storage;
1727 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001728 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001729 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1730 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1731 SkRect tmp(r);
1732 tmp.sort();
1733
1734 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001735 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001736 return;
1737 }
1738 }
reed@google.com4b226022011-01-11 18:32:13 +00001739
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001740 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001741
1742 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001743 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001744 }
1745
reed@google.com4e2b3d32011-04-07 14:18:59 +00001746 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001747}
1748
reed41af9662015-01-05 07:49:08 -08001749void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001750 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001751 SkRect storage;
1752 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001753 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001754 bounds = &paint.computeFastBounds(oval, &storage);
1755 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001756 return;
1757 }
1758 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001759
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001760 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001761
1762 while (iter.next()) {
1763 iter.fDevice->drawOval(iter, oval, looper.paint());
1764 }
1765
1766 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001767}
1768
reed41af9662015-01-05 07:49:08 -08001769void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001770 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001771 SkRect storage;
1772 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001773 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001774 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1775 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001776 return;
1777 }
1778 }
1779
1780 if (rrect.isRect()) {
1781 // call the non-virtual version
1782 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001783 return;
1784 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001785 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001786 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1787 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001788 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001789
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001790 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001791
1792 while (iter.next()) {
1793 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1794 }
1795
1796 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001797}
1798
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001799void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1800 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001801 SkRect storage;
1802 const SkRect* bounds = NULL;
1803 if (paint.canComputeFastBounds()) {
1804 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1805 if (this->quickReject(*bounds)) {
1806 return;
1807 }
1808 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001809
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001810 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001811
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001812 while (iter.next()) {
1813 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1814 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001815
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001816 LOOPER_END
1817}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001818
reed41af9662015-01-05 07:49:08 -08001819void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001820 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001821 if (!path.isFinite()) {
1822 return;
1823 }
1824
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001825 SkRect storage;
1826 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001827 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001828 const SkRect& pathBounds = path.getBounds();
1829 bounds = &paint.computeFastBounds(pathBounds, &storage);
1830 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001831 return;
1832 }
1833 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001834
1835 const SkRect& r = path.getBounds();
1836 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001837 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001838 this->internalDrawPaint(paint);
1839 }
1840 return;
1841 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001842
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001843 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001844
1845 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001846 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001847 }
1848
reed@google.com4e2b3d32011-04-07 14:18:59 +00001849 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001850}
1851
kkinnunena9baa652015-03-05 06:33:54 -08001852void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001853 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
kkinnunena9baa652015-03-05 06:33:54 -08001854 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001855}
1856
reed41af9662015-01-05 07:49:08 -08001857void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1858 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001859 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
kkinnunena9baa652015-03-05 06:33:54 -08001860 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001861}
1862
reed41af9662015-01-05 07:49:08 -08001863void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001864 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001865 SkDEBUGCODE(bitmap.validate();)
1866
reed@google.com3d608122011-11-21 15:16:16 +00001867 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001868 SkRect bounds = {
1869 x, y,
1870 x + SkIntToScalar(bitmap.width()),
1871 y + SkIntToScalar(bitmap.height())
1872 };
1873 if (paint) {
1874 (void)paint->computeFastBounds(bounds, &bounds);
1875 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001876 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001877 return;
1878 }
1879 }
reed@google.com4b226022011-01-11 18:32:13 +00001880
reed@android.com8a1c16f2008-12-17 15:59:43 +00001881 SkMatrix matrix;
1882 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001883 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001884}
1885
reed@google.com9987ec32011-09-07 11:57:52 +00001886// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00001887void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001888 const SkRect& dst, const SkPaint* paint,
1889 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001890 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001891 return;
1892 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001893
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001894 SkRect storage;
1895 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00001896 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001897 if (paint) {
1898 bounds = &paint->computeFastBounds(dst, &storage);
1899 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001900 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001901 return;
1902 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001903 }
reed@google.com3d608122011-11-21 15:16:16 +00001904
reed@google.com33535f32012-09-25 15:37:50 +00001905 SkLazyPaint lazy;
1906 if (NULL == paint) {
1907 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001908 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001909
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001910 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001911
reed@google.com33535f32012-09-25 15:37:50 +00001912 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001913 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00001914 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001915
reed@google.com33535f32012-09-25 15:37:50 +00001916 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001917}
1918
reed41af9662015-01-05 07:49:08 -08001919void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1920 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08001921 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00001922 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001923 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00001924}
1925
reed@google.com9987ec32011-09-07 11:57:52 +00001926void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1927 const SkIRect& center, const SkRect& dst,
1928 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001929 if (bitmap.drawsNothing()) {
1930 return;
1931 }
reed@google.com3d608122011-11-21 15:16:16 +00001932 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00001933 SkRect storage;
1934 const SkRect* bounds = &dst;
1935 if (paint) {
1936 bounds = &paint->computeFastBounds(dst, &storage);
1937 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001938 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001939 return;
1940 }
1941 }
1942
reed@google.com9987ec32011-09-07 11:57:52 +00001943 const int32_t w = bitmap.width();
1944 const int32_t h = bitmap.height();
1945
1946 SkIRect c = center;
1947 // pin center to the bounds of the bitmap
1948 c.fLeft = SkMax32(0, center.fLeft);
1949 c.fTop = SkMax32(0, center.fTop);
1950 c.fRight = SkPin32(center.fRight, c.fLeft, w);
1951 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1952
reed@google.com71121732012-09-18 15:14:33 +00001953 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001954 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00001955 };
1956 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001957 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00001958 };
reed@google.com9987ec32011-09-07 11:57:52 +00001959 SkScalar dstX[4] = {
1960 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
1961 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
1962 };
1963 SkScalar dstY[4] = {
1964 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
1965 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
1966 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001967
reed@google.com9987ec32011-09-07 11:57:52 +00001968 if (dstX[1] > dstX[2]) {
1969 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
1970 dstX[2] = dstX[1];
1971 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001972
reed@google.com9987ec32011-09-07 11:57:52 +00001973 if (dstY[1] > dstY[2]) {
1974 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
1975 dstY[2] = dstY[1];
1976 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001977
reed@google.com9987ec32011-09-07 11:57:52 +00001978 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00001979 SkRect s, d;
1980
reed@google.com9987ec32011-09-07 11:57:52 +00001981 s.fTop = srcY[y];
1982 s.fBottom = srcY[y+1];
1983 d.fTop = dstY[y];
1984 d.fBottom = dstY[y+1];
1985 for (int x = 0; x < 3; x++) {
1986 s.fLeft = srcX[x];
1987 s.fRight = srcX[x+1];
1988 d.fLeft = dstX[x];
1989 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001990 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00001991 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00001992 }
1993 }
1994}
1995
reed41af9662015-01-05 07:49:08 -08001996void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1997 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001998 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00001999 SkDEBUGCODE(bitmap.validate();)
2000
2001 // Need a device entry-point, so gpu can use a mesh
2002 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2003}
2004
reed@google.comf67e4cf2011-03-15 20:56:58 +00002005class SkDeviceFilteredPaint {
2006public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002007 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002008 uint32_t filteredFlags = device->filterTextFlags(paint);
2009 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002010 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002011 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002012 fPaint = newPaint;
2013 } else {
2014 fPaint = &paint;
2015 }
2016 }
2017
reed@google.comf67e4cf2011-03-15 20:56:58 +00002018 const SkPaint& paint() const { return *fPaint; }
2019
2020private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002021 const SkPaint* fPaint;
2022 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002023};
2024
bungeman@google.com52c748b2011-08-22 21:30:43 +00002025void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2026 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002027 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002028 draw.fDevice->drawRect(draw, r, paint);
2029 } else {
2030 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002031 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002032 draw.fDevice->drawRect(draw, r, p);
2033 }
2034}
2035
2036void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2037 const char text[], size_t byteLength,
2038 SkScalar x, SkScalar y) {
2039 SkASSERT(byteLength == 0 || text != NULL);
2040
2041 // nothing to draw
2042 if (text == NULL || byteLength == 0 ||
2043 draw.fClip->isEmpty() ||
2044 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2045 return;
2046 }
2047
2048 SkScalar width = 0;
2049 SkPoint start;
2050
2051 start.set(0, 0); // to avoid warning
2052 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2053 SkPaint::kStrikeThruText_Flag)) {
2054 width = paint.measureText(text, byteLength);
2055
2056 SkScalar offsetX = 0;
2057 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2058 offsetX = SkScalarHalf(width);
2059 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2060 offsetX = width;
2061 }
2062 start.set(x - offsetX, y);
2063 }
2064
2065 if (0 == width) {
2066 return;
2067 }
2068
2069 uint32_t flags = paint.getFlags();
2070
2071 if (flags & (SkPaint::kUnderlineText_Flag |
2072 SkPaint::kStrikeThruText_Flag)) {
2073 SkScalar textSize = paint.getTextSize();
2074 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2075 SkRect r;
2076
2077 r.fLeft = start.fX;
2078 r.fRight = start.fX + width;
2079
2080 if (flags & SkPaint::kUnderlineText_Flag) {
2081 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2082 start.fY);
2083 r.fTop = offset;
2084 r.fBottom = offset + height;
2085 DrawRect(draw, paint, r, textSize);
2086 }
2087 if (flags & SkPaint::kStrikeThruText_Flag) {
2088 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2089 start.fY);
2090 r.fTop = offset;
2091 r.fBottom = offset + height;
2092 DrawRect(draw, paint, r, textSize);
2093 }
2094 }
2095}
2096
reed@google.come0d9ce82014-04-23 04:00:17 +00002097void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2098 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002099 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002100
2101 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002102 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002103 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002104 DrawTextDecorations(iter, dfp.paint(),
2105 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002106 }
2107
reed@google.com4e2b3d32011-04-07 14:18:59 +00002108 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002109}
2110
reed@google.come0d9ce82014-04-23 04:00:17 +00002111void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2112 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002113 SkPoint textOffset = SkPoint::Make(0, 0);
2114
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002115 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002116
reed@android.com8a1c16f2008-12-17 15:59:43 +00002117 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002118 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002119 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002120 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002121 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002122
reed@google.com4e2b3d32011-04-07 14:18:59 +00002123 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002124}
2125
reed@google.come0d9ce82014-04-23 04:00:17 +00002126void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2127 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002128
2129 SkPoint textOffset = SkPoint::Make(0, constY);
2130
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002131 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002132
reed@android.com8a1c16f2008-12-17 15:59:43 +00002133 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002134 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002135 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002136 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002137 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002138
reed@google.com4e2b3d32011-04-07 14:18:59 +00002139 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002140}
2141
reed@google.come0d9ce82014-04-23 04:00:17 +00002142void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2143 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002144 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002145
reed@android.com8a1c16f2008-12-17 15:59:43 +00002146 while (iter.next()) {
2147 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002148 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002149 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002150
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002151 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002152}
2153
fmalita00d5c2c2014-08-21 08:53:26 -07002154void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2155 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002156
fmalita85d5eb92015-03-04 11:20:12 -08002157 SkRect storage;
2158 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002159 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002160 storage = blob->bounds().makeOffset(x, y);
2161 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002162
fmalita85d5eb92015-03-04 11:20:12 -08002163 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002164 return;
2165 }
2166 }
2167
fmalita024f9962015-03-03 19:08:17 -08002168 // We cannot filter in the looper as we normally do, because the paint is
2169 // incomplete at this point (text-related attributes are embedded within blob run paints).
2170 SkDrawFilter* drawFilter = fMCRec->fFilter;
2171 fMCRec->fFilter = NULL;
2172
fmalita85d5eb92015-03-04 11:20:12 -08002173 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002174
fmalitaaa1b9122014-08-28 14:32:24 -07002175 while (iter.next()) {
2176 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002177 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002178 }
2179
fmalitaaa1b9122014-08-28 14:32:24 -07002180 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002181
2182 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002183}
2184
reed@google.come0d9ce82014-04-23 04:00:17 +00002185// These will become non-virtual, so they always call the (virtual) onDraw... method
2186void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2187 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002188 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002189 this->onDrawText(text, byteLength, x, y, paint);
2190}
2191void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2192 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002193 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002194 this->onDrawPosText(text, byteLength, pos, paint);
2195}
2196void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2197 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002198 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002199 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2200}
2201void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2202 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002203 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002204 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2205}
fmalita00d5c2c2014-08-21 08:53:26 -07002206void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2207 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002208 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002209 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002210 this->onDrawTextBlob(blob, x, y, paint);
2211 }
2212}
reed@google.come0d9ce82014-04-23 04:00:17 +00002213
reed41af9662015-01-05 07:49:08 -08002214void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2215 const SkPoint verts[], const SkPoint texs[],
2216 const SkColor colors[], SkXfermode* xmode,
2217 const uint16_t indices[], int indexCount,
2218 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002219 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002220 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002221
reed@android.com8a1c16f2008-12-17 15:59:43 +00002222 while (iter.next()) {
2223 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002224 colors, xmode, indices, indexCount,
2225 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002226 }
reed@google.com4b226022011-01-11 18:32:13 +00002227
reed@google.com4e2b3d32011-04-07 14:18:59 +00002228 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002229}
2230
dandovb3c9d1c2014-08-12 08:34:29 -07002231void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2232 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002233 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002234 if (NULL == cubics) {
2235 return;
2236 }
mtklein6cfa73a2014-08-13 13:33:49 -07002237
dandovecfff212014-08-04 10:02:00 -07002238 // Since a patch is always within the convex hull of the control points, we discard it when its
2239 // bounding rectangle is completely outside the current clip.
2240 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002241 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002242 if (this->quickReject(bounds)) {
2243 return;
2244 }
mtklein6cfa73a2014-08-13 13:33:49 -07002245
dandovb3c9d1c2014-08-12 08:34:29 -07002246 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2247}
2248
2249void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2250 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2251
dandovecfff212014-08-04 10:02:00 -07002252 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002253
dandovecfff212014-08-04 10:02:00 -07002254 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002255 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002256 }
mtklein6cfa73a2014-08-13 13:33:49 -07002257
dandovecfff212014-08-04 10:02:00 -07002258 LOOPER_END
2259}
2260
reed3cb38402015-02-06 08:36:15 -08002261void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002262 if (dr && !this->quickReject(dr->getBounds())) {
2263 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002264 }
2265}
2266
reed3cb38402015-02-06 08:36:15 -08002267void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002268 dr->draw(this);
2269}
2270
reed@android.com8a1c16f2008-12-17 15:59:43 +00002271//////////////////////////////////////////////////////////////////////////////
2272// These methods are NOT virtual, and therefore must call back into virtual
2273// methods, rather than actually drawing themselves.
2274//////////////////////////////////////////////////////////////////////////////
2275
2276void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002277 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002278 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002279 SkPaint paint;
2280
2281 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002282 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002283 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002284 }
2285 this->drawPaint(paint);
2286}
2287
reed@android.com845fdac2009-06-23 03:01:32 +00002288void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002289 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290 SkPaint paint;
2291
2292 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002293 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002294 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002295 }
2296 this->drawPaint(paint);
2297}
2298
2299void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002300 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002301 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002302
reed@android.com8a1c16f2008-12-17 15:59:43 +00002303 pt.set(x, y);
2304 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2305}
2306
2307void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002308 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002309 SkPoint pt;
2310 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002311
reed@android.com8a1c16f2008-12-17 15:59:43 +00002312 pt.set(x, y);
2313 paint.setColor(color);
2314 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2315}
2316
2317void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2318 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002319 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002320 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002321
reed@android.com8a1c16f2008-12-17 15:59:43 +00002322 pts[0].set(x0, y0);
2323 pts[1].set(x1, y1);
2324 this->drawPoints(kLines_PointMode, 2, pts, paint);
2325}
2326
2327void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2328 SkScalar right, SkScalar bottom,
2329 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002330 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002331 SkRect r;
2332
2333 r.set(left, top, right, bottom);
2334 this->drawRect(r, paint);
2335}
2336
2337void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2338 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002339 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002340 if (radius < 0) {
2341 radius = 0;
2342 }
2343
2344 SkRect r;
2345 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002346 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002347}
2348
2349void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2350 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002351 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002352 if (rx > 0 && ry > 0) {
2353 if (paint.canComputeFastBounds()) {
2354 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002355 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002356 return;
2357 }
2358 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002359 SkRRect rrect;
2360 rrect.setRectXY(r, rx, ry);
2361 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002362 } else {
2363 this->drawRect(r, paint);
2364 }
2365}
2366
reed@android.com8a1c16f2008-12-17 15:59:43 +00002367void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2368 SkScalar sweepAngle, bool useCenter,
2369 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002370 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002371 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2372 this->drawOval(oval, paint);
2373 } else {
2374 SkPath path;
2375 if (useCenter) {
2376 path.moveTo(oval.centerX(), oval.centerY());
2377 }
2378 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2379 if (useCenter) {
2380 path.close();
2381 }
2382 this->drawPath(path, paint);
2383 }
2384}
2385
2386void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2387 const SkPath& path, SkScalar hOffset,
2388 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002389 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002390 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002391
reed@android.com8a1c16f2008-12-17 15:59:43 +00002392 matrix.setTranslate(hOffset, vOffset);
2393 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2394}
2395
reed@android.comf76bacf2009-05-13 14:00:33 +00002396///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002397void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002398 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002399 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002400 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002401 }
2402}
2403
reedd5fa1a42014-08-09 11:08:05 -07002404void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002405 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002406 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002407 if (matrix && matrix->isIdentity()) {
2408 matrix = NULL;
2409 }
2410 this->onDrawPicture(picture, matrix, paint);
2411 }
2412}
robertphillips9b14f262014-06-04 05:40:44 -07002413
reedd5fa1a42014-08-09 11:08:05 -07002414void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2415 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002416 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002417 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002418 // Canvas has to first give the device the opportunity to render
2419 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002420 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002421 return; // the device has rendered the entire picture
2422 }
2423 }
2424
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002425 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002426
robertphillipsc5ba71d2014-09-04 08:42:50 -07002427 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002428}
2429
reed@android.com8a1c16f2008-12-17 15:59:43 +00002430///////////////////////////////////////////////////////////////////////////////
2431///////////////////////////////////////////////////////////////////////////////
2432
2433SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002434 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002435
2436 SkASSERT(canvas);
2437
2438 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2439 fDone = !fImpl->next();
2440}
2441
2442SkCanvas::LayerIter::~LayerIter() {
2443 fImpl->~SkDrawIter();
2444}
2445
2446void SkCanvas::LayerIter::next() {
2447 fDone = !fImpl->next();
2448}
2449
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002450SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002451 return fImpl->getDevice();
2452}
2453
2454const SkMatrix& SkCanvas::LayerIter::matrix() const {
2455 return fImpl->getMatrix();
2456}
2457
2458const SkPaint& SkCanvas::LayerIter::paint() const {
2459 const SkPaint* paint = fImpl->getPaint();
2460 if (NULL == paint) {
2461 paint = &fDefaultPaint;
2462 }
2463 return *paint;
2464}
2465
2466const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2467int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2468int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002469
2470///////////////////////////////////////////////////////////////////////////////
2471
fmalitac3b589a2014-06-05 12:40:07 -07002472SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002473
2474///////////////////////////////////////////////////////////////////////////////
2475
2476static bool supported_for_raster_canvas(const SkImageInfo& info) {
2477 switch (info.alphaType()) {
2478 case kPremul_SkAlphaType:
2479 case kOpaque_SkAlphaType:
2480 break;
2481 default:
2482 return false;
2483 }
2484
2485 switch (info.colorType()) {
2486 case kAlpha_8_SkColorType:
2487 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002488 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002489 break;
2490 default:
2491 return false;
2492 }
2493
2494 return true;
2495}
2496
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002497SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2498 if (!supported_for_raster_canvas(info)) {
2499 return NULL;
2500 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002501
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002502 SkBitmap bitmap;
2503 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2504 return NULL;
2505 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002506 return SkNEW_ARGS(SkCanvas, (bitmap));
2507}
reedd5fa1a42014-08-09 11:08:05 -07002508
2509///////////////////////////////////////////////////////////////////////////////
2510
2511SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002512 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002513 : fCanvas(canvas)
2514 , fSaveCount(canvas->getSaveCount())
2515{
bsalomon49f085d2014-09-05 13:34:00 -07002516 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002517 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002518 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002519 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002520 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002521 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002522 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002523 canvas->save();
2524 }
mtklein6cfa73a2014-08-13 13:33:49 -07002525
bsalomon49f085d2014-09-05 13:34:00 -07002526 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002527 canvas->concat(*matrix);
2528 }
2529}
2530
2531SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2532 fCanvas->restoreToCount(fSaveCount);
2533}