blob: 55b3b7ba7a7987ec878e82692eb94fc94cf98506 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
8#include "SkCanvas.h"
reedd5fa1a42014-08-09 11:08:05 -07009#include "SkCanvasPriv.h"
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000010#include "SkBitmapDevice.h"
senorblanco@chromium.org9c397442012-09-27 21:57:45 +000011#include "SkDeviceImageFilterProxy.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080013#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkDrawFilter.h"
15#include "SkDrawLooper.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080016#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070017#include "SkImage.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000018#include "SkMetaData.h"
caryclark@google.com45a75fb2013-04-25 13:34:40 +000019#include "SkPathOps.h"
dandovb3c9d1c2014-08-12 08:34:29 -070020#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000021#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000022#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080023#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000024#include "SkRRect.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000025#include "SkSmallAllocator.h"
reed@google.com97af1a62012-08-28 12:19:02 +000026#include "SkSurface_Base.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000027#include "SkTemplates.h"
fmalita7ba7aa72014-08-29 09:46:36 -070028#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000029#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000030#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080031#include "SkTraceEvent.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000032#include "SkUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000033
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000034#if SK_SUPPORT_GPU
35#include "GrRenderTarget.h"
36#endif
37
reedd990e2f2014-12-22 11:58:30 -080038static bool gIgnoreSaveLayerBounds;
39void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
40 gIgnoreSaveLayerBounds = ignore;
41}
42bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
43 return gIgnoreSaveLayerBounds;
44}
45
reed0acf1b42014-12-22 16:12:38 -080046static bool gTreatSpriteAsBitmap;
47void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
48 gTreatSpriteAsBitmap = spriteAsBitmap;
49}
50bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
51 return gTreatSpriteAsBitmap;
52}
53
reed@google.comda17f752012-08-16 18:27:05 +000054// experimental for faster tiled drawing...
55//#define SK_ENABLE_CLIP_QUICKREJECT
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000056
reed@android.com8a1c16f2008-12-17 15:59:43 +000057//#define SK_TRACE_SAVERESTORE
58
59#ifdef SK_TRACE_SAVERESTORE
60 static int gLayerCounter;
61 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
62 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
63
64 static int gRecCounter;
65 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
66 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
67
68 static int gCanvasCounter;
69 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
70 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
71#else
72 #define inc_layer()
73 #define dec_layer()
74 #define inc_rec()
75 #define dec_rec()
76 #define inc_canvas()
77 #define dec_canvas()
78#endif
79
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +000080typedef SkTLazy<SkPaint> SkLazyPaint;
81
reed@google.com97af1a62012-08-28 12:19:02 +000082void SkCanvas::predrawNotify() {
83 if (fSurfaceBase) {
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +000084 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
reed@google.com97af1a62012-08-28 12:19:02 +000085 }
86}
87
reed@android.com8a1c16f2008-12-17 15:59:43 +000088///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000089
reed4a8126e2014-09-22 07:29:03 -070090static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
91 const uint32_t propFlags = props.flags();
92 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
93 flags &= ~SkPaint::kDither_Flag;
94 }
95 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
96 flags &= ~SkPaint::kAntiAlias_Flag;
97 }
98 return flags;
99}
100
101///////////////////////////////////////////////////////////////////////////////
102
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000103/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 The clip/matrix/proc are fields that reflect the top of the save/restore
105 stack. Whenever the canvas changes, it marks a dirty flag, and then before
106 these are used (assuming we're not on a layer) we rebuild these cache
107 values: they reflect the top of the save stack, but translated and clipped
108 by the device's XY offset and bitmap-bounds.
109*/
110struct DeviceCM {
111 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000112 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000113 SkRasterClip fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 const SkMatrix* fMatrix;
reed@google.com6f8f2922011-03-04 22:27:10 +0000115 SkPaint* fPaint; // may be null (in the future)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116
reed96e657d2015-03-10 17:30:07 -0700117 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reedd9544982014-09-09 18:46:22 -0700118 bool conservativeRasterClip)
119 : fNext(NULL)
120 , fClip(conservativeRasterClip)
121 {
122 if (NULL != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000124 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125 }
reed@google.com4b226022011-01-11 18:32:13 +0000126 fDevice = device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000128 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000130 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700131 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000132 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 fDevice->unref();
134 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000135 SkDELETE(fPaint);
136 }
reed@google.com4b226022011-01-11 18:32:13 +0000137
reed@google.com045e62d2011-10-24 12:19:46 +0000138 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
139 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000140 int x = fDevice->getOrigin().x();
141 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 int width = fDevice->width();
143 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000144
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 if ((x | y) == 0) {
146 fMatrix = &totalMatrix;
147 fClip = totalClip;
148 } else {
149 fMatrixStorage = totalMatrix;
150 fMatrixStorage.postTranslate(SkIntToScalar(-x),
151 SkIntToScalar(-y));
152 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000153
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 totalClip.translate(-x, -y, &fClip);
155 }
156
reed@google.com045e62d2011-10-24 12:19:46 +0000157 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158
159 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000160
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000162 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163 SkRegion::kDifference_Op);
164 }
reed@google.com4b226022011-01-11 18:32:13 +0000165
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000166 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
167
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168#ifdef SK_DEBUG
169 if (!fClip.isEmpty()) {
170 SkIRect deviceR;
171 deviceR.set(0, 0, width, height);
172 SkASSERT(deviceR.contains(fClip.getBounds()));
173 }
174#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000175 }
176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177private:
bsalomon@google.com0e354aa2012-10-08 20:44:25 +0000178 SkMatrix fMatrixStorage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179};
180
181/* This is the record we keep for each save/restore level in the stack.
182 Since a level optionally copies the matrix and/or stack, we have pointers
183 for these fields. If the value is copied for this level, the copy is
184 stored in the ...Storage field, and the pointer points to that. If the
185 value is not copied for this level, we ignore ...Storage, and just point
186 at the corresponding value in the previous level in the stack.
187*/
188class SkCanvas::MCRec {
189public:
reed1f836ee2014-07-07 07:49:34 -0700190 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700191 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 /* If there are any layers in the stack, this points to the top-most
193 one that is at or below this level in the stack (so we know what
194 bitmap/device to draw into from this level. This value is NOT
195 reference counted, since the real owner is either our fLayer field,
196 or a previous one in a lower level.)
197 */
reed2ff1fce2014-12-11 07:07:37 -0800198 DeviceCM* fTopLayer;
199 SkRasterClip fRasterClip;
200 SkMatrix fMatrix;
201 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202
reedd9544982014-09-09 18:46:22 -0700203 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
reedd9544982014-09-09 18:46:22 -0700204 fFilter = NULL;
205 fLayer = NULL;
206 fTopLayer = NULL;
reed2ff1fce2014-12-11 07:07:37 -0800207 fMatrix.reset();
208 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700209
reedd9544982014-09-09 18:46:22 -0700210 // don't bother initializing fNext
211 inc_rec();
212 }
reed2ff1fce2014-12-11 07:07:37 -0800213 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700214 fFilter = SkSafeRef(prev.fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215 fLayer = NULL;
reedd9544982014-09-09 18:46:22 -0700216 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800217 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700218
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 // don't bother initializing fNext
220 inc_rec();
221 }
222 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000223 SkSafeUnref(fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 SkDELETE(fLayer);
225 dec_rec();
226 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227};
228
229class SkDrawIter : public SkDraw {
230public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000231 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000232 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000233 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 canvas->updateDeviceCMCache();
235
joshualittde358a92015-02-05 08:19:35 -0800236 fClipStack = canvas->fClipStack.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000238 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 }
reed@google.com4b226022011-01-11 18:32:13 +0000240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 bool next() {
242 // skip over recs with empty clips
243 if (fSkipEmptyClips) {
244 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
245 fCurrLayer = fCurrLayer->fNext;
246 }
247 }
248
reed@google.comf68c5e22012-02-24 16:38:58 +0000249 const DeviceCM* rec = fCurrLayer;
250 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251
252 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000253 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
254 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 fDevice = rec->fDevice;
256 fBitmap = &fDevice->accessBitmap(true);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000258 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259
260 fCurrLayer = rec->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261 // fCurrLayer may be NULL now
reed@android.com199f1082009-06-10 02:12:47 +0000262
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 return true;
264 }
265 return false;
266 }
reed@google.com4b226022011-01-11 18:32:13 +0000267
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000268 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000269 int getX() const { return fDevice->getOrigin().x(); }
270 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 const SkMatrix& getMatrix() const { return *fMatrix; }
272 const SkRegion& getClip() const { return *fClip; }
273 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000274
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275private:
276 SkCanvas* fCanvas;
277 const DeviceCM* fCurrLayer;
278 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 SkBool8 fSkipEmptyClips;
280
281 typedef SkDraw INHERITED;
282};
283
284/////////////////////////////////////////////////////////////////////////////
285
286class AutoDrawLooper {
287public:
reed4a8126e2014-09-22 07:29:03 -0700288 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000289 bool skipLayerForImageFilter = false,
290 const SkRect* bounds = NULL) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000291 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700293 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000294 fSaveCount = canvas->getSaveCount();
reed@google.com8926b162012-03-23 15:36:36 +0000295 fDoClearImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000296 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297
reed1b110d62015-03-08 18:47:13 -0700298 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
reed@google.com8926b162012-03-23 15:36:36 +0000299 SkPaint tmp;
reed1b110d62015-03-08 18:47:13 -0700300 tmp.setImageFilter(fOrigPaint.getImageFilter());
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000301 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
302 true, SkCanvas::kFullLayer_SaveLayerStrategy);
reed@google.com8926b162012-03-23 15:36:36 +0000303 // we'll clear the imageFilter for the actual draws in next(), so
304 // it will only be applied during the restore().
305 fDoClearImageFilter = true;
306 }
307
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000308 if (SkDrawLooper* looper = paint.getLooper()) {
309 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
310 looper->contextSize());
311 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000312 fIsSimple = false;
313 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000314 fLooperContext = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000315 // can we be marked as simple?
316 fIsSimple = !fFilter && !fDoClearImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000317 }
piotaixrb5fae932014-09-24 13:03:30 -0700318
reed4a8126e2014-09-22 07:29:03 -0700319 uint32_t oldFlags = paint.getFlags();
320 fNewPaintFlags = filter_paint_flags(props, oldFlags);
321 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reed1b110d62015-03-08 18:47:13 -0700322 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700323 paint->setFlags(fNewPaintFlags);
324 fPaint = paint;
325 // if we're not simple, doNext() will take care of calling setFlags()
326 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000327 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000328
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 ~AutoDrawLooper() {
reed@google.com8926b162012-03-23 15:36:36 +0000330 if (fDoClearImageFilter) {
331 fCanvas->internalRestore();
332 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000333 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000335
reed@google.com4e2b3d32011-04-07 14:18:59 +0000336 const SkPaint& paint() const {
337 SkASSERT(fPaint);
338 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000340
reed@google.com129ec222012-05-15 13:24:09 +0000341 bool next(SkDrawFilter::Type drawType) {
342 if (fDone) {
343 return false;
344 } else if (fIsSimple) {
345 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000346 return !fPaint->nothingToDraw();
347 } else {
348 return this->doNext(drawType);
349 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000350 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000351
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352private:
reed1b110d62015-03-08 18:47:13 -0700353 SkLazyPaint fLazyPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000354 SkCanvas* fCanvas;
355 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000356 SkDrawFilter* fFilter;
357 const SkPaint* fPaint;
358 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700359 uint32_t fNewPaintFlags;
reed@google.com8926b162012-03-23 15:36:36 +0000360 bool fDoClearImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000361 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000362 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000363 SkDrawLooper::Context* fLooperContext;
364 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000365
366 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367};
368
reed@google.com129ec222012-05-15 13:24:09 +0000369bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
reed@google.com632e1a22011-10-06 12:37:00 +0000370 fPaint = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000371 SkASSERT(!fIsSimple);
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000372 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000373
reed1b110d62015-03-08 18:47:13 -0700374 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700375 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000376
377 if (fDoClearImageFilter) {
378 paint->setImageFilter(NULL);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000379 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000380
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000381 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000382 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000383 return false;
384 }
385 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000386 if (!fFilter->filter(paint, drawType)) {
387 fDone = true;
388 return false;
389 }
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000390 if (NULL == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000391 // no looper means we only draw once
392 fDone = true;
393 }
394 }
395 fPaint = paint;
396
397 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000398 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000399 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000400 }
401
402 // call this after any possible paint modifiers
403 if (fPaint->nothingToDraw()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000404 fPaint = NULL;
405 return false;
406 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000407 return true;
408}
409
reed@android.com8a1c16f2008-12-17 15:59:43 +0000410////////// macros to place around the internal draw calls //////////////////
411
reed@google.com8926b162012-03-23 15:36:36 +0000412#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000413 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700414 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000415 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000416 SkDrawIter iter(this);
417
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000418#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000419 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700420 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000421 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000423
reed@google.com4e2b3d32011-04-07 14:18:59 +0000424#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000425
426////////////////////////////////////////////////////////////////////////////
427
reedd9544982014-09-09 18:46:22 -0700428SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
429 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
reed@google.comc0784db2013-12-13 21:16:12 +0000430 fCachedLocalClipBounds.setEmpty();
431 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000432 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000433 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700434 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800435 fSaveCount = 1;
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000436 fMetaData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437
438 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700439 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440
reed96e657d2015-03-10 17:30:07 -0700441 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, NULL, NULL, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443
reed@google.com97af1a62012-08-28 12:19:02 +0000444 fSurfaceBase = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000445
joshualittde358a92015-02-05 08:19:35 -0800446 fClipStack.reset(SkNEW(SkClipStack));
447
reedf92c8662014-08-18 08:02:43 -0700448 if (device) {
reedb2db8982014-11-13 12:41:02 -0800449 device->initForRootLayer(fProps.pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700450 if (device->forceConservativeRasterClip()) {
451 fConservativeRasterClip = true;
452 }
reedf92c8662014-08-18 08:02:43 -0700453 device->onAttachToCanvas(this);
454 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800455 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700456 }
457 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000458}
459
reed@google.comcde92112011-07-06 20:00:52 +0000460SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000461 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700462 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000463{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000464 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000465
reedd9544982014-09-09 18:46:22 -0700466 this->init(NULL, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000467}
468
reedd9544982014-09-09 18:46:22 -0700469static SkBitmap make_nopixels(int width, int height) {
470 SkBitmap bitmap;
471 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
472 return bitmap;
473}
474
475class SkNoPixelsBitmapDevice : public SkBitmapDevice {
476public:
reed78e27682014-11-19 08:04:34 -0800477 SkNoPixelsBitmapDevice(const SkIRect& bounds)
478 : INHERITED(make_nopixels(bounds.width(), bounds.height()))
479 {
480 this->setOrigin(bounds.x(), bounds.y());
481 }
reedd9544982014-09-09 18:46:22 -0700482
483private:
piotaixrb5fae932014-09-24 13:03:30 -0700484
reedd9544982014-09-09 18:46:22 -0700485 typedef SkBitmapDevice INHERITED;
486};
487
reed96a857e2015-01-25 10:33:58 -0800488SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000489 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800490 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000491{
492 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700493
reed78e27682014-11-19 08:04:34 -0800494 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
495 (SkIRect::MakeWH(width, height))), kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700496}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000497
reed78e27682014-11-19 08:04:34 -0800498SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700499 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700500 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700501{
502 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700503
reed78e27682014-11-19 08:04:34 -0800504 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds)), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700505}
506
reed4a8126e2014-09-22 07:29:03 -0700507SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700508 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700509 , fProps(SkSurfacePropsCopyOrDefault(props))
reedd9544982014-09-09 18:46:22 -0700510{
511 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700512
reedd9544982014-09-09 18:46:22 -0700513 this->init(device, flags);
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000514}
515
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000516SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000517 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700518 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000519{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000520 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700521
reedd9544982014-09-09 18:46:22 -0700522 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523}
524
reed4a8126e2014-09-22 07:29:03 -0700525SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700526 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700527 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700528{
529 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700530
reed4a8126e2014-09-22 07:29:03 -0700531 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
532 this->init(device, kDefault_InitFlags);
533}
reed29c857d2014-09-21 10:25:07 -0700534
reed4a8126e2014-09-22 07:29:03 -0700535SkCanvas::SkCanvas(const SkBitmap& bitmap)
536 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
537 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
538{
539 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700540
reed4a8126e2014-09-22 07:29:03 -0700541 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
542 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000543}
544
545SkCanvas::~SkCanvas() {
546 // free up the contents of our deque
547 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000548
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549 this->internalRestore(); // restore the last, since we're going away
550
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000551 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000552
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553 dec_canvas();
554}
555
reed@android.com8a1c16f2008-12-17 15:59:43 +0000556SkDrawFilter* SkCanvas::getDrawFilter() const {
557 return fMCRec->fFilter;
558}
559
560SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
561 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
562 return filter;
563}
564
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000565SkMetaData& SkCanvas::getMetaData() {
566 // metadata users are rare, so we lazily allocate it. If that changes we
567 // can decide to just make it a field in the device (rather than a ptr)
568 if (NULL == fMetaData) {
569 fMetaData = new SkMetaData;
570 }
571 return *fMetaData;
572}
573
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574///////////////////////////////////////////////////////////////////////////////
575
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000576void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000577 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000578 if (device) {
579 device->flush();
580 }
581}
582
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000583SkISize SkCanvas::getTopLayerSize() const {
584 SkBaseDevice* d = this->getTopDevice();
585 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
586}
587
588SkIPoint SkCanvas::getTopLayerOrigin() const {
589 SkBaseDevice* d = this->getTopDevice();
590 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
591}
592
593SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000594 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000595 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
596}
597
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000598SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000599 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000600 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601 SkASSERT(rec && rec->fLayer);
602 return rec->fLayer->fDevice;
603}
604
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000605SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000606 if (updateMatrixClip) {
607 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
608 }
reed@google.com9266fed2011-03-30 00:18:03 +0000609 return fMCRec->fTopLayer->fDevice;
610}
611
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000612bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
613 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
614 return false;
615 }
616
617 bool weAllocated = false;
618 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700619 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000620 return false;
621 }
622 weAllocated = true;
623 }
624
625 SkBitmap bm(*bitmap);
626 bm.lockPixels();
627 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
628 return true;
629 }
630
631 if (weAllocated) {
632 bitmap->setPixelRef(NULL);
633 }
634 return false;
635}
reed@google.com51df9e32010-12-23 19:29:18 +0000636
bsalomon@google.comc6980972011-11-02 19:57:21 +0000637bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000638 SkIRect r = srcRect;
639 const SkISize size = this->getBaseLayerSize();
640 if (!r.intersect(0, 0, size.width(), size.height())) {
641 bitmap->reset();
642 return false;
643 }
644
reed84825042014-09-02 12:50:45 -0700645 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000646 // bitmap will already be reset.
647 return false;
648 }
649 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
650 bitmap->reset();
651 return false;
652 }
653 return true;
654}
655
reed96472de2014-12-10 09:53:42 -0800656bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000657 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000658 if (!device) {
659 return false;
660 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000661 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800662
reed96472de2014-12-10 09:53:42 -0800663 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
664 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000665 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000666 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000667
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000668 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800669 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000670}
671
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000672bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
673 if (bitmap.getTexture()) {
674 return false;
675 }
676 SkBitmap bm(bitmap);
677 bm.lockPixels();
678 if (bm.getPixels()) {
679 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
680 }
681 return false;
682}
683
684bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
685 int x, int y) {
686 switch (origInfo.colorType()) {
687 case kUnknown_SkColorType:
688 case kIndex_8_SkColorType:
689 return false;
690 default:
691 break;
692 }
693 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
694 return false;
695 }
696
697 const SkISize size = this->getBaseLayerSize();
698 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
699 if (!target.intersect(0, 0, size.width(), size.height())) {
700 return false;
701 }
702
703 SkBaseDevice* device = this->getDevice();
704 if (!device) {
705 return false;
706 }
707
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000708 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700709 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000710
711 // if x or y are negative, then we have to adjust pixels
712 if (x > 0) {
713 x = 0;
714 }
715 if (y > 0) {
716 y = 0;
717 }
718 // here x,y are either 0 or negative
719 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
720
reed4af35f32014-06-27 17:47:49 -0700721 // Tell our owning surface to bump its generation ID
722 this->predrawNotify();
723
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000724 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000725 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000726}
reed@google.com51df9e32010-12-23 19:29:18 +0000727
junov@google.com4370aed2012-01-18 16:21:08 +0000728SkCanvas* SkCanvas::canvasForDrawIter() {
729 return this;
730}
731
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732//////////////////////////////////////////////////////////////////////////////
733
reed@android.com8a1c16f2008-12-17 15:59:43 +0000734void SkCanvas::updateDeviceCMCache() {
735 if (fDeviceCMDirty) {
736 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700737 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000739
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740 if (NULL == layer->fNext) { // only one layer
joshualittde358a92015-02-05 08:19:35 -0800741 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000743 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000744 do {
joshualittde358a92015-02-05 08:19:35 -0800745 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746 } while ((layer = layer->fNext) != NULL);
747 }
748 fDeviceCMDirty = false;
749 }
750}
751
reed@android.com8a1c16f2008-12-17 15:59:43 +0000752///////////////////////////////////////////////////////////////////////////////
753
reed2ff1fce2014-12-11 07:07:37 -0800754void SkCanvas::checkForDeferredSave() {
755 if (fMCRec->fDeferredSaveCount > 0) {
756 fMCRec->fDeferredSaveCount -= 1;
757 this->doSave();
758 }
759}
760
reedf0090cb2014-11-26 08:55:51 -0800761int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800762#ifdef SK_DEBUG
763 int count = 0;
764 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
765 for (;;) {
766 const MCRec* rec = (const MCRec*)iter.next();
767 if (!rec) {
768 break;
769 }
770 count += 1 + rec->fDeferredSaveCount;
771 }
772 SkASSERT(count == fSaveCount);
773#endif
774 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800775}
776
777int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800778 fSaveCount += 1;
779 fMCRec->fDeferredSaveCount += 1;
780 return this->getSaveCount() - 1; // return our prev value
781}
782
783void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800784 this->willSave();
reed2ff1fce2014-12-11 07:07:37 -0800785 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800786}
787
788void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800789 if (fMCRec->fDeferredSaveCount > 0) {
790 SkASSERT(fSaveCount > 1);
791 fSaveCount -= 1;
792 fMCRec->fDeferredSaveCount -= 1;
793 } else {
794 // check for underflow
795 if (fMCStack.count() > 1) {
796 this->willRestore();
797 SkASSERT(fSaveCount > 1);
798 fSaveCount -= 1;
799 this->internalRestore();
800 this->didRestore();
801 }
reedf0090cb2014-11-26 08:55:51 -0800802 }
803}
804
805void SkCanvas::restoreToCount(int count) {
806 // sanity check
807 if (count < 1) {
808 count = 1;
809 }
mtkleinf0f14112014-12-12 08:46:25 -0800810
reedf0090cb2014-11-26 08:55:51 -0800811 int n = this->getSaveCount() - count;
812 for (int i = 0; i < n; ++i) {
813 this->restore();
814 }
815}
816
reed2ff1fce2014-12-11 07:07:37 -0800817void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000818 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700819 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000820 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000821
joshualittde358a92015-02-05 08:19:35 -0800822 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823}
824
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000826#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000828#else
829 return true;
830#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831}
832
junov@chromium.orga907ac32012-02-24 21:54:07 +0000833bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700834 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000835 SkIRect clipBounds;
reed44124652015-03-11 04:02:20 -0700836 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);
reed44124652015-03-11 04:02:20 -0700845 // Filters may grow the bounds beyond the device bounds.
846 op = SkRegion::kReplace_Op;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000847 }
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)) {
reed9b3aa542015-03-11 08:47:12 -0700857 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700858 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000859 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000860 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000861 }
862 } else { // no user bounds, so just use the clip
863 ir = clipBounds;
864 }
865
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000866 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700867 fCachedLocalClipBoundsDirty = true;
reed44124652015-03-11 04:02:20 -0700868 fClipStack->clipDevRect(ir, op);
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000869 // early exit if the clip is now empty
reed44124652015-03-11 04:02:20 -0700870 if (!fMCRec->fRasterClip.op(ir, op)) {
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000871 return false;
872 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000873 }
874
875 if (intersection) {
876 *intersection = ir;
877 }
878 return true;
879}
880
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000881int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800882 if (gIgnoreSaveLayerBounds) {
883 bounds = NULL;
884 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000885 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reed2ff1fce2014-12-11 07:07:37 -0800886 fSaveCount += 1;
887 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy);
888 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000889}
890
reed2ff1fce2014-12-11 07:07:37 -0800891int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800892 if (gIgnoreSaveLayerBounds) {
893 bounds = NULL;
894 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000895 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reed2ff1fce2014-12-11 07:07:37 -0800896 fSaveCount += 1;
897 this->internalSaveLayer(bounds, paint, flags, false, strategy);
898 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000899}
900
reed2ff1fce2014-12-11 07:07:37 -0800901void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000902 bool justForImageFilter, SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000903#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000904 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000905#endif
906
junov@chromium.orga907ac32012-02-24 21:54:07 +0000907 // do this before we create the layer. We don't call the public save() since
908 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -0800909 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000910
911 fDeviceCMDirty = true;
912
913 SkIRect ir;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000914 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -0800915 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000916 }
917
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000918 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
919 // the clipRectBounds() call above?
920 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -0800921 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000922 }
923
reed@google.comb55deeb2012-01-06 14:43:09 +0000924 // Kill the imagefilter if our device doesn't allow it
925 SkLazyPaint lazyP;
926 if (paint && paint->getImageFilter()) {
927 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
reed@google.com8926b162012-03-23 15:36:36 +0000928 if (justForImageFilter) {
929 // early exit if the layer was just for the imageFilter
reed2ff1fce2014-12-11 07:07:37 -0800930 return;
reed@google.com8926b162012-03-23 15:36:36 +0000931 }
reed@google.comb55deeb2012-01-06 14:43:09 +0000932 SkPaint* p = lazyP.set(*paint);
933 p->setImageFilter(NULL);
934 paint = p;
935 }
936 }
937
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000938 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
939 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
940 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000941
reedb2db8982014-11-13 12:41:02 -0800942 SkBaseDevice* device = this->getTopDevice();
943 if (NULL == device) {
944 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800945 return;
reed@google.com76dd2772012-01-05 21:15:07 +0000946 }
reedb2db8982014-11-13 12:41:02 -0800947
948 SkBaseDevice::Usage usage = SkBaseDevice::kSaveLayer_Usage;
949 if (paint && paint->getImageFilter()) {
950 usage = SkBaseDevice::kImageFilter_Usage;
951 }
952 device = device->onCreateCompatibleDevice(SkBaseDevice::CreateInfo(info, usage,
953 fProps.pixelGeometry()));
bungeman@google.come25c6842011-08-17 14:53:54 +0000954 if (NULL == device) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800955 SkErrorInternals::SetError( kInternalError_SkError,
956 "Unable to create device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800957 return;
bungeman@google.come25c6842011-08-17 14:53:54 +0000958 }
bsalomon@google.come97f0852011-06-17 13:10:25 +0000959
reed@google.com6f8f2922011-03-04 22:27:10 +0000960 device->setOrigin(ir.fLeft, ir.fTop);
reed96e657d2015-03-10 17:30:07 -0700961 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962 device->unref();
963
964 layer->fNext = fMCRec->fTopLayer;
965 fMCRec->fLayer = layer;
966 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967}
968
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000969int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
970 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
971}
972
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
974 SaveFlags flags) {
975 if (0xFF == alpha) {
976 return this->saveLayer(bounds, NULL, flags);
977 } else {
978 SkPaint tmpPaint;
979 tmpPaint.setAlpha(alpha);
980 return this->saveLayer(bounds, &tmpPaint, flags);
981 }
982}
983
reed@android.com8a1c16f2008-12-17 15:59:43 +0000984void SkCanvas::internalRestore() {
985 SkASSERT(fMCStack.count() != 0);
986
987 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +0000988 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989
joshualittde358a92015-02-05 08:19:35 -0800990 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +0000991
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000992 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000993 DeviceCM* layer = fMCRec->fLayer; // may be null
994 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
995 fMCRec->fLayer = NULL;
996
997 // now do the normal restore()
998 fMCRec->~MCRec(); // balanced in save()
999 fMCStack.pop_back();
1000 fMCRec = (MCRec*)fMCStack.back();
1001
1002 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1003 since if we're being recorded, we don't want to record this (the
1004 recorder will have already recorded the restore).
1005 */
bsalomon49f085d2014-09-05 13:34:00 -07001006 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001007 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001008 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001009 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1010 layer->fPaint);
1011 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001012 fDeviceCMDirty = true;
1013 }
1014 SkDELETE(layer);
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001015 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001016}
1017
reed4a8126e2014-09-22 07:29:03 -07001018SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1019 if (NULL == props) {
1020 props = &fProps;
1021 }
1022 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001023}
1024
reed4a8126e2014-09-22 07:29:03 -07001025SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001026 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001027 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001028}
1029
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001030SkImageInfo SkCanvas::imageInfo() const {
1031 SkBaseDevice* dev = this->getDevice();
1032 if (dev) {
1033 return dev->imageInfo();
1034 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001035 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001036 }
1037}
1038
1039const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1040 return this->onPeekPixels(info, rowBytes);
1041}
1042
1043const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1044 SkBaseDevice* dev = this->getDevice();
1045 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1046}
1047
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001048void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1049 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1050 if (pixels && origin) {
1051 *origin = this->getTopDevice(false)->getOrigin();
1052 }
1053 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001054}
1055
1056void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1057 SkBaseDevice* dev = this->getTopDevice();
1058 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1059}
1060
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001061SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1062 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1063 if (NULL == fAddr) {
1064 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001065 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001066 return; // failure, fAddr is NULL
1067 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001068 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1069 return; // failure, fAddr is NULL
1070 }
1071 fAddr = fBitmap.getPixels();
1072 fRowBytes = fBitmap.rowBytes();
1073 }
1074 SkASSERT(fAddr); // success
1075}
1076
1077bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1078 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001079 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001080 } else {
1081 bitmap->reset();
1082 return false;
1083 }
1084}
1085
reed@android.com8a1c16f2008-12-17 15:59:43 +00001086/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001087void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001089 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001090 return;
1091 }
1092
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001093 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001094 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001095 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001096 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001097
1098 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001099
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001100 SkRect storage;
1101 const SkRect* bounds = NULL;
1102 if (paint && paint->canComputeFastBounds()) {
1103 bitmap.getBounds(&storage);
1104 matrix.mapRect(&storage);
1105 bounds = &paint->computeFastBounds(storage, &storage);
1106 }
1107
1108 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001109
1110 while (iter.next()) {
1111 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1112 }
1113
1114 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001115}
1116
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001117void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed@google.com8926b162012-03-23 15:36:36 +00001118 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001119 SkPaint tmp;
1120 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001121 paint = &tmp;
1122 }
reed@google.com4b226022011-01-11 18:32:13 +00001123
reed@google.com8926b162012-03-23 15:36:36 +00001124 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001125 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001126 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001127 paint = &looper.paint();
1128 SkImageFilter* filter = paint->getImageFilter();
1129 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001130 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001131 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001132 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001133 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001134 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001135 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001136 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001137 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001138 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001139 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001140 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001141 SkPaint tmpUnfiltered(*paint);
1142 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001143 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1144 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001145 }
1146 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001147 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001148 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001150 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001151}
1152
reed41af9662015-01-05 07:49:08 -08001153void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001154 if (gTreatSpriteAsBitmap) {
1155 this->save();
1156 this->resetMatrix();
1157 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1158 this->restore();
1159 return;
1160 }
1161
danakj9881d632014-11-26 12:41:06 -08001162 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001163 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001164 return;
1165 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001166 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001167
reed@google.com8926b162012-03-23 15:36:36 +00001168 SkPaint tmp;
1169 if (NULL == paint) {
1170 paint = &tmp;
1171 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001172
reed@google.com8926b162012-03-23 15:36:36 +00001173 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001174
reed@google.com8926b162012-03-23 15:36:36 +00001175 while (iter.next()) {
1176 paint = &looper.paint();
1177 SkImageFilter* filter = paint->getImageFilter();
1178 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1179 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001180 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001181 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001182 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001183 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001184 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001185 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001186 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001187 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001188 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001189 SkPaint tmpUnfiltered(*paint);
1190 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001191 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001192 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001193 }
1194 } else {
1195 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1196 }
1197 }
1198 LOOPER_END
1199}
1200
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001202void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001203 SkMatrix m;
1204 m.setTranslate(dx, dy);
1205 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001206}
1207
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001208void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001209 SkMatrix m;
1210 m.setScale(sx, sy);
1211 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212}
1213
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001214void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001215 SkMatrix m;
1216 m.setRotate(degrees);
1217 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218}
1219
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001220void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001221 SkMatrix m;
1222 m.setSkew(sx, sy);
1223 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001224}
1225
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001226void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001227 if (matrix.isIdentity()) {
1228 return;
1229 }
1230
reed2ff1fce2014-12-11 07:07:37 -08001231 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001232 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001233 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001234 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001235
1236 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001237}
1238
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001240 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001242 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001243 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001244 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245}
1246
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247void SkCanvas::resetMatrix() {
1248 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001249
reed@android.com8a1c16f2008-12-17 15:59:43 +00001250 matrix.reset();
1251 this->setMatrix(matrix);
1252}
1253
1254//////////////////////////////////////////////////////////////////////////////
1255
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001256void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001257 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001258 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1259 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001260}
1261
1262void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001263#ifdef SK_ENABLE_CLIP_QUICKREJECT
1264 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001265 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001266 return false;
1267 }
1268
reed@google.com3b3e8952012-08-16 20:53:31 +00001269 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001270 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001271 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001272
1273 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001274 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001275 }
1276 }
1277#endif
1278
reed@google.com5c3d1472011-02-22 19:12:23 +00001279 AutoValidateClip avc(this);
1280
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001282 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001283 if (!fAllowSoftClip) {
1284 edgeStyle = kHard_ClipEdgeStyle;
1285 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001286
reed1f836ee2014-07-07 07:49:34 -07001287 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001288 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001289 // the matrix. This means we don't have to a) make a path, and b) tell
1290 // the region code to scan-convert the path, only to discover that it
1291 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001292 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293
reed1f836ee2014-07-07 07:49:34 -07001294 fMCRec->fMatrix.mapRect(&r, rect);
joshualittde358a92015-02-05 08:19:35 -08001295 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001296 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001298 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001299 // and clip against that, since it can handle any matrix. However, to
1300 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1301 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 SkPath path;
1303
1304 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001305 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001306 }
1307}
1308
reed73e714e2014-09-04 09:02:23 -07001309static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1310 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001311 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001312}
1313
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001314void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001315 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001316 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001317 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001318 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1319 } else {
1320 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001321 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001322}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001323
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001324void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001325 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001326 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001327 AutoValidateClip avc(this);
1328
1329 fDeviceCMDirty = true;
1330 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001331 if (!fAllowSoftClip) {
1332 edgeStyle = kHard_ClipEdgeStyle;
1333 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001334
joshualittde358a92015-02-05 08:19:35 -08001335 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001336
1337 SkPath devPath;
1338 devPath.addRRect(transformedRRect);
1339
reed73e714e2014-09-04 09:02:23 -07001340 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001341 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001342 }
1343
1344 SkPath path;
1345 path.addRRect(rrect);
1346 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001347 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001348}
1349
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001350void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001351 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001352 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1353 SkRect r;
1354 if (!path.isInverseFillType() && path.isRect(&r)) {
1355 this->onClipRect(r, op, edgeStyle);
1356 } else {
1357 this->onClipPath(path, op, edgeStyle);
1358 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001359}
1360
1361void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001362#ifdef SK_ENABLE_CLIP_QUICKREJECT
1363 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001364 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001365 return false;
1366 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001367
reed@google.com3b3e8952012-08-16 20:53:31 +00001368 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001369 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001370 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001371
reed@google.comda17f752012-08-16 18:27:05 +00001372 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001373 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001374 }
1375 }
1376#endif
1377
reed@google.com5c3d1472011-02-22 19:12:23 +00001378 AutoValidateClip avc(this);
1379
reed@android.com8a1c16f2008-12-17 15:59:43 +00001380 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001381 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001382 if (!fAllowSoftClip) {
1383 edgeStyle = kHard_ClipEdgeStyle;
1384 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385
1386 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001387 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001388
reed@google.comfe701122011-11-08 19:41:23 +00001389 // Check if the transfomation, or the original path itself
1390 // made us empty. Note this can also happen if we contained NaN
1391 // values. computing the bounds detects this, and will set our
1392 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1393 if (devPath.getBounds().isEmpty()) {
1394 // resetting the path will remove any NaN or other wanky values
1395 // that might upset our scan converter.
1396 devPath.reset();
1397 }
1398
reed@google.com5c3d1472011-02-22 19:12:23 +00001399 // if we called path.swap() we could avoid a deep copy of this path
joshualittde358a92015-02-05 08:19:35 -08001400 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001401
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001402 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001403 bool clipIsAA = getClipStack()->asPath(&devPath);
1404 if (clipIsAA) {
1405 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001406 }
fmalita1a481fe2015-02-04 07:39:34 -08001407
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001408 op = SkRegion::kReplace_Op;
1409 }
1410
reed73e714e2014-09-04 09:02:23 -07001411 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412}
1413
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001414void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001415 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001416 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001417}
1418
1419void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001420 AutoValidateClip avc(this);
1421
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001423 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424
reed@google.com5c3d1472011-02-22 19:12:23 +00001425 // todo: signal fClipStack that we have a region, and therefore (I guess)
1426 // we have to ignore it, and use the region directly?
joshualittde358a92015-02-05 08:19:35 -08001427 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001428
reed1f836ee2014-07-07 07:49:34 -07001429 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001430}
1431
reed@google.com819c9212011-02-23 18:56:55 +00001432#ifdef SK_DEBUG
1433void SkCanvas::validateClip() const {
1434 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001435 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001436 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001437 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001438 return;
1439 }
1440
reed@google.com819c9212011-02-23 18:56:55 +00001441 SkIRect ir;
1442 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001443 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001444
joshualittde358a92015-02-05 08:19:35 -08001445 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001446 const SkClipStack::Element* element;
1447 while ((element = iter.next()) != NULL) {
1448 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001449 case SkClipStack::Element::kRect_Type:
1450 element->getRect().round(&ir);
1451 tmpClip.op(ir, element->getOp());
1452 break;
1453 case SkClipStack::Element::kEmpty_Type:
1454 tmpClip.setEmpty();
1455 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001456 default: {
1457 SkPath path;
1458 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001459 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001460 break;
1461 }
reed@google.com819c9212011-02-23 18:56:55 +00001462 }
1463 }
reed@google.com819c9212011-02-23 18:56:55 +00001464}
1465#endif
1466
reed@google.com90c07ea2012-04-13 13:50:27 +00001467void SkCanvas::replayClips(ClipVisitor* visitor) const {
joshualittde358a92015-02-05 08:19:35 -08001468 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001469 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001470
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001471 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001472 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001473 }
1474}
1475
reed@google.com5c3d1472011-02-22 19:12:23 +00001476///////////////////////////////////////////////////////////////////////////////
1477
reed@google.com754de5f2014-02-24 19:38:20 +00001478bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001479 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001480}
1481
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001482bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001483 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001484}
1485
reed@google.com3b3e8952012-08-16 20:53:31 +00001486bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001487 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001488 return true;
1489
reed1f836ee2014-07-07 07:49:34 -07001490 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001491 return true;
1492 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001493
reed1f836ee2014-07-07 07:49:34 -07001494 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001495 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001496 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001497 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001498 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001499 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001500
reed@android.coma380ae42009-07-21 01:17:02 +00001501 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001502 // TODO: should we use | instead, or compare all 4 at once?
1503 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001504 return true;
1505 }
reed@google.comc0784db2013-12-13 21:16:12 +00001506 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001507 return true;
1508 }
1509 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001510 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001511}
1512
reed@google.com3b3e8952012-08-16 20:53:31 +00001513bool SkCanvas::quickReject(const SkPath& path) const {
1514 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001515}
1516
reed@google.com3b3e8952012-08-16 20:53:31 +00001517bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001518 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001519 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001520 return false;
1521 }
1522
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001523 SkMatrix inverse;
1524 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001525 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001526 if (bounds) {
1527 bounds->setEmpty();
1528 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001529 return false;
1530 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001531
bsalomon49f085d2014-09-05 13:34:00 -07001532 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001533 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001534 // adjust it outwards in case we are antialiasing
1535 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001536
reed@google.com8f4d2302013-12-17 16:44:46 +00001537 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1538 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001539 inverse.mapRect(bounds, r);
1540 }
1541 return true;
1542}
1543
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001544bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001545 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001546 if (clip.isEmpty()) {
1547 if (bounds) {
1548 bounds->setEmpty();
1549 }
1550 return false;
1551 }
1552
bsalomon49f085d2014-09-05 13:34:00 -07001553 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001554 *bounds = clip.getBounds();
1555 }
1556 return true;
1557}
1558
reed@android.com8a1c16f2008-12-17 15:59:43 +00001559const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001560 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001561}
1562
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001563const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001564 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001565}
1566
reed@google.com9c135db2014-03-12 18:28:35 +00001567GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1568 SkBaseDevice* dev = this->getTopDevice();
1569 return dev ? dev->accessRenderTarget() : NULL;
1570}
1571
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001572GrContext* SkCanvas::getGrContext() {
1573#if SK_SUPPORT_GPU
1574 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001575 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001576 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001577 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001578 return renderTarget->getContext();
1579 }
1580 }
1581#endif
1582
1583 return NULL;
1584
1585}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001586
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001587void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1588 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001589 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001590 if (outer.isEmpty()) {
1591 return;
1592 }
1593 if (inner.isEmpty()) {
1594 this->drawRRect(outer, paint);
1595 return;
1596 }
1597
1598 // We don't have this method (yet), but technically this is what we should
1599 // be able to assert...
1600 // SkASSERT(outer.contains(inner));
1601 //
1602 // For now at least check for containment of bounds
1603 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1604
1605 this->onDrawDRRect(outer, inner, paint);
1606}
1607
reed41af9662015-01-05 07:49:08 -08001608// These need to stop being virtual -- clients need to override the onDraw... versions
1609
1610void SkCanvas::drawPaint(const SkPaint& paint) {
1611 this->onDrawPaint(paint);
1612}
1613
1614void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1615 this->onDrawRect(r, paint);
1616}
1617
1618void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1619 this->onDrawOval(r, paint);
1620}
1621
1622void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1623 this->onDrawRRect(rrect, paint);
1624}
1625
1626void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1627 this->onDrawPoints(mode, count, pts, paint);
1628}
1629
1630void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1631 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1632 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1633 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1634 indices, indexCount, paint);
1635}
1636
1637void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1638 this->onDrawPath(path, paint);
1639}
1640
1641void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1642 this->onDrawImage(image, dx, dy, paint);
1643}
1644
1645void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1646 const SkPaint* paint) {
1647 this->onDrawImageRect(image, src, dst, paint);
1648}
1649
1650void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1651 this->onDrawBitmap(bitmap, dx, dy, paint);
1652}
1653
1654void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1655 const SkPaint* paint, DrawBitmapRectFlags flags) {
1656 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1657}
1658
1659void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1660 const SkPaint* paint) {
1661 this->onDrawBitmapNine(bitmap, center, dst, paint);
1662}
1663
1664void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
1665 this->onDrawSprite(bitmap, left, top, paint);
1666}
1667
reed@android.com8a1c16f2008-12-17 15:59:43 +00001668//////////////////////////////////////////////////////////////////////////////
1669// These are the virtual drawing methods
1670//////////////////////////////////////////////////////////////////////////////
1671
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001672void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001673 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001674 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1675 }
1676}
1677
reed41af9662015-01-05 07:49:08 -08001678void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001679 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001680 this->internalDrawPaint(paint);
1681}
1682
1683void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001684 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001685
1686 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001687 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001688 }
1689
reed@google.com4e2b3d32011-04-07 14:18:59 +00001690 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001691}
1692
reed41af9662015-01-05 07:49:08 -08001693void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1694 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001695 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001696 if ((long)count <= 0) {
1697 return;
1698 }
1699
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001700 SkRect r, storage;
1701 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001702 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001703 // special-case 2 points (common for drawing a single line)
1704 if (2 == count) {
1705 r.set(pts[0], pts[1]);
1706 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001707 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001708 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001709 bounds = &paint.computeFastStrokeBounds(r, &storage);
1710 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001711 return;
1712 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001713 }
reed@google.coma584aed2012-05-16 14:06:02 +00001714
reed@android.com8a1c16f2008-12-17 15:59:43 +00001715 SkASSERT(pts != NULL);
1716
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001717 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001718
reed@android.com8a1c16f2008-12-17 15:59:43 +00001719 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001720 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001721 }
reed@google.com4b226022011-01-11 18:32:13 +00001722
reed@google.com4e2b3d32011-04-07 14:18:59 +00001723 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001724}
1725
reed41af9662015-01-05 07:49:08 -08001726void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001727 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001728 SkRect storage;
1729 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001730 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001731 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1732 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1733 SkRect tmp(r);
1734 tmp.sort();
1735
1736 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001737 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001738 return;
1739 }
1740 }
reed@google.com4b226022011-01-11 18:32:13 +00001741
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001742 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001743
1744 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001745 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001746 }
1747
reed@google.com4e2b3d32011-04-07 14:18:59 +00001748 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001749}
1750
reed41af9662015-01-05 07:49:08 -08001751void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001752 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001753 SkRect storage;
1754 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001755 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001756 bounds = &paint.computeFastBounds(oval, &storage);
1757 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001758 return;
1759 }
1760 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001761
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001762 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001763
1764 while (iter.next()) {
1765 iter.fDevice->drawOval(iter, oval, looper.paint());
1766 }
1767
1768 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001769}
1770
reed41af9662015-01-05 07:49:08 -08001771void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001772 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001773 SkRect storage;
1774 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001775 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001776 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1777 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001778 return;
1779 }
1780 }
1781
1782 if (rrect.isRect()) {
1783 // call the non-virtual version
1784 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001785 return;
1786 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001787 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001788 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1789 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001790 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001791
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001792 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001793
1794 while (iter.next()) {
1795 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1796 }
1797
1798 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001799}
1800
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001801void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1802 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001803 SkRect storage;
1804 const SkRect* bounds = NULL;
1805 if (paint.canComputeFastBounds()) {
1806 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1807 if (this->quickReject(*bounds)) {
1808 return;
1809 }
1810 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001811
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001812 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001813
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001814 while (iter.next()) {
1815 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1816 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001817
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001818 LOOPER_END
1819}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001820
reed41af9662015-01-05 07:49:08 -08001821void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001822 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001823 if (!path.isFinite()) {
1824 return;
1825 }
1826
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001827 SkRect storage;
1828 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001829 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001830 const SkRect& pathBounds = path.getBounds();
1831 bounds = &paint.computeFastBounds(pathBounds, &storage);
1832 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001833 return;
1834 }
1835 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001836
1837 const SkRect& r = path.getBounds();
1838 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001839 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001840 this->internalDrawPaint(paint);
1841 }
1842 return;
1843 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001844
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001845 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001846
1847 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001848 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001849 }
1850
reed@google.com4e2b3d32011-04-07 14:18:59 +00001851 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001852}
1853
kkinnunena9baa652015-03-05 06:33:54 -08001854void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001855 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
kkinnunena9baa652015-03-05 06:33:54 -08001856 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001857}
1858
reed41af9662015-01-05 07:49:08 -08001859void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1860 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001861 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
kkinnunena9baa652015-03-05 06:33:54 -08001862 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001863}
1864
reed41af9662015-01-05 07:49:08 -08001865void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001866 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001867 SkDEBUGCODE(bitmap.validate();)
1868
reed@google.com3d608122011-11-21 15:16:16 +00001869 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001870 SkRect bounds = {
1871 x, y,
1872 x + SkIntToScalar(bitmap.width()),
1873 y + SkIntToScalar(bitmap.height())
1874 };
1875 if (paint) {
1876 (void)paint->computeFastBounds(bounds, &bounds);
1877 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001878 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001879 return;
1880 }
1881 }
reed@google.com4b226022011-01-11 18:32:13 +00001882
reed@android.com8a1c16f2008-12-17 15:59:43 +00001883 SkMatrix matrix;
1884 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001885 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001886}
1887
reed@google.com9987ec32011-09-07 11:57:52 +00001888// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00001889void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001890 const SkRect& dst, const SkPaint* paint,
1891 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001892 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001893 return;
1894 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001895
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001896 SkRect storage;
1897 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00001898 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001899 if (paint) {
1900 bounds = &paint->computeFastBounds(dst, &storage);
1901 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001902 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001903 return;
1904 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001905 }
reed@google.com3d608122011-11-21 15:16:16 +00001906
reed@google.com33535f32012-09-25 15:37:50 +00001907 SkLazyPaint lazy;
1908 if (NULL == paint) {
1909 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001910 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001911
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001912 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001913
reed@google.com33535f32012-09-25 15:37:50 +00001914 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001915 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00001916 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001917
reed@google.com33535f32012-09-25 15:37:50 +00001918 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001919}
1920
reed41af9662015-01-05 07:49:08 -08001921void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1922 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08001923 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00001924 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001925 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00001926}
1927
reed@google.com9987ec32011-09-07 11:57:52 +00001928void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1929 const SkIRect& center, const SkRect& dst,
1930 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001931 if (bitmap.drawsNothing()) {
1932 return;
1933 }
reed@google.com3d608122011-11-21 15:16:16 +00001934 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00001935 SkRect storage;
1936 const SkRect* bounds = &dst;
1937 if (paint) {
1938 bounds = &paint->computeFastBounds(dst, &storage);
1939 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001940 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001941 return;
1942 }
1943 }
1944
reed@google.com9987ec32011-09-07 11:57:52 +00001945 const int32_t w = bitmap.width();
1946 const int32_t h = bitmap.height();
1947
1948 SkIRect c = center;
1949 // pin center to the bounds of the bitmap
1950 c.fLeft = SkMax32(0, center.fLeft);
1951 c.fTop = SkMax32(0, center.fTop);
1952 c.fRight = SkPin32(center.fRight, c.fLeft, w);
1953 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1954
reed@google.com71121732012-09-18 15:14:33 +00001955 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001956 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00001957 };
1958 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001959 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00001960 };
reed@google.com9987ec32011-09-07 11:57:52 +00001961 SkScalar dstX[4] = {
1962 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
1963 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
1964 };
1965 SkScalar dstY[4] = {
1966 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
1967 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
1968 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001969
reed@google.com9987ec32011-09-07 11:57:52 +00001970 if (dstX[1] > dstX[2]) {
1971 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
1972 dstX[2] = dstX[1];
1973 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001974
reed@google.com9987ec32011-09-07 11:57:52 +00001975 if (dstY[1] > dstY[2]) {
1976 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
1977 dstY[2] = dstY[1];
1978 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001979
reed@google.com9987ec32011-09-07 11:57:52 +00001980 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00001981 SkRect s, d;
1982
reed@google.com9987ec32011-09-07 11:57:52 +00001983 s.fTop = srcY[y];
1984 s.fBottom = srcY[y+1];
1985 d.fTop = dstY[y];
1986 d.fBottom = dstY[y+1];
1987 for (int x = 0; x < 3; x++) {
1988 s.fLeft = srcX[x];
1989 s.fRight = srcX[x+1];
1990 d.fLeft = dstX[x];
1991 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001992 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00001993 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00001994 }
1995 }
1996}
1997
reed41af9662015-01-05 07:49:08 -08001998void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1999 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002000 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002001 SkDEBUGCODE(bitmap.validate();)
2002
2003 // Need a device entry-point, so gpu can use a mesh
2004 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2005}
2006
reed@google.comf67e4cf2011-03-15 20:56:58 +00002007class SkDeviceFilteredPaint {
2008public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002009 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002010 uint32_t filteredFlags = device->filterTextFlags(paint);
2011 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002012 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002013 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002014 fPaint = newPaint;
2015 } else {
2016 fPaint = &paint;
2017 }
2018 }
2019
reed@google.comf67e4cf2011-03-15 20:56:58 +00002020 const SkPaint& paint() const { return *fPaint; }
2021
2022private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002023 const SkPaint* fPaint;
2024 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002025};
2026
bungeman@google.com52c748b2011-08-22 21:30:43 +00002027void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2028 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002029 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002030 draw.fDevice->drawRect(draw, r, paint);
2031 } else {
2032 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002033 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002034 draw.fDevice->drawRect(draw, r, p);
2035 }
2036}
2037
2038void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2039 const char text[], size_t byteLength,
2040 SkScalar x, SkScalar y) {
2041 SkASSERT(byteLength == 0 || text != NULL);
2042
2043 // nothing to draw
2044 if (text == NULL || byteLength == 0 ||
2045 draw.fClip->isEmpty() ||
2046 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2047 return;
2048 }
2049
2050 SkScalar width = 0;
2051 SkPoint start;
2052
2053 start.set(0, 0); // to avoid warning
2054 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2055 SkPaint::kStrikeThruText_Flag)) {
2056 width = paint.measureText(text, byteLength);
2057
2058 SkScalar offsetX = 0;
2059 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2060 offsetX = SkScalarHalf(width);
2061 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2062 offsetX = width;
2063 }
2064 start.set(x - offsetX, y);
2065 }
2066
2067 if (0 == width) {
2068 return;
2069 }
2070
2071 uint32_t flags = paint.getFlags();
2072
2073 if (flags & (SkPaint::kUnderlineText_Flag |
2074 SkPaint::kStrikeThruText_Flag)) {
2075 SkScalar textSize = paint.getTextSize();
2076 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2077 SkRect r;
2078
2079 r.fLeft = start.fX;
2080 r.fRight = start.fX + width;
2081
2082 if (flags & SkPaint::kUnderlineText_Flag) {
2083 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2084 start.fY);
2085 r.fTop = offset;
2086 r.fBottom = offset + height;
2087 DrawRect(draw, paint, r, textSize);
2088 }
2089 if (flags & SkPaint::kStrikeThruText_Flag) {
2090 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2091 start.fY);
2092 r.fTop = offset;
2093 r.fBottom = offset + height;
2094 DrawRect(draw, paint, r, textSize);
2095 }
2096 }
2097}
2098
reed@google.come0d9ce82014-04-23 04:00:17 +00002099void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2100 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002101 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002102
2103 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002104 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002105 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002106 DrawTextDecorations(iter, dfp.paint(),
2107 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002108 }
2109
reed@google.com4e2b3d32011-04-07 14:18:59 +00002110 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002111}
2112
reed@google.come0d9ce82014-04-23 04:00:17 +00002113void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2114 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002115 SkPoint textOffset = SkPoint::Make(0, 0);
2116
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002117 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002118
reed@android.com8a1c16f2008-12-17 15:59:43 +00002119 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002120 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002121 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002122 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002123 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002124
reed@google.com4e2b3d32011-04-07 14:18:59 +00002125 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002126}
2127
reed@google.come0d9ce82014-04-23 04:00:17 +00002128void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2129 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002130
2131 SkPoint textOffset = SkPoint::Make(0, constY);
2132
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002133 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002134
reed@android.com8a1c16f2008-12-17 15:59:43 +00002135 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002136 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002137 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002138 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002139 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002140
reed@google.com4e2b3d32011-04-07 14:18:59 +00002141 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002142}
2143
reed@google.come0d9ce82014-04-23 04:00:17 +00002144void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2145 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002146 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002147
reed@android.com8a1c16f2008-12-17 15:59:43 +00002148 while (iter.next()) {
2149 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002150 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002151 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002152
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002153 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002154}
2155
fmalita00d5c2c2014-08-21 08:53:26 -07002156void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2157 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002158
fmalita85d5eb92015-03-04 11:20:12 -08002159 SkRect storage;
2160 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002161 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002162 storage = blob->bounds().makeOffset(x, y);
2163 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002164
fmalita85d5eb92015-03-04 11:20:12 -08002165 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002166 return;
2167 }
2168 }
2169
fmalita024f9962015-03-03 19:08:17 -08002170 // We cannot filter in the looper as we normally do, because the paint is
2171 // incomplete at this point (text-related attributes are embedded within blob run paints).
2172 SkDrawFilter* drawFilter = fMCRec->fFilter;
2173 fMCRec->fFilter = NULL;
2174
fmalita85d5eb92015-03-04 11:20:12 -08002175 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002176
fmalitaaa1b9122014-08-28 14:32:24 -07002177 while (iter.next()) {
2178 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002179 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002180 }
2181
fmalitaaa1b9122014-08-28 14:32:24 -07002182 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002183
2184 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002185}
2186
reed@google.come0d9ce82014-04-23 04:00:17 +00002187// These will become non-virtual, so they always call the (virtual) onDraw... method
2188void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2189 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002190 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002191 this->onDrawText(text, byteLength, x, y, paint);
2192}
2193void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2194 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002195 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002196 this->onDrawPosText(text, byteLength, pos, paint);
2197}
2198void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2199 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002200 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002201 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2202}
2203void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2204 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002205 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002206 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2207}
fmalita00d5c2c2014-08-21 08:53:26 -07002208void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2209 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002210 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002211 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002212 this->onDrawTextBlob(blob, x, y, paint);
2213 }
2214}
reed@google.come0d9ce82014-04-23 04:00:17 +00002215
reed41af9662015-01-05 07:49:08 -08002216void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2217 const SkPoint verts[], const SkPoint texs[],
2218 const SkColor colors[], SkXfermode* xmode,
2219 const uint16_t indices[], int indexCount,
2220 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002221 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002222 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002223
reed@android.com8a1c16f2008-12-17 15:59:43 +00002224 while (iter.next()) {
2225 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002226 colors, xmode, indices, indexCount,
2227 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002228 }
reed@google.com4b226022011-01-11 18:32:13 +00002229
reed@google.com4e2b3d32011-04-07 14:18:59 +00002230 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002231}
2232
dandovb3c9d1c2014-08-12 08:34:29 -07002233void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2234 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002235 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002236 if (NULL == cubics) {
2237 return;
2238 }
mtklein6cfa73a2014-08-13 13:33:49 -07002239
dandovecfff212014-08-04 10:02:00 -07002240 // Since a patch is always within the convex hull of the control points, we discard it when its
2241 // bounding rectangle is completely outside the current clip.
2242 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002243 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002244 if (this->quickReject(bounds)) {
2245 return;
2246 }
mtklein6cfa73a2014-08-13 13:33:49 -07002247
dandovb3c9d1c2014-08-12 08:34:29 -07002248 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2249}
2250
2251void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2252 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2253
dandovecfff212014-08-04 10:02:00 -07002254 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002255
dandovecfff212014-08-04 10:02:00 -07002256 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002257 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002258 }
mtklein6cfa73a2014-08-13 13:33:49 -07002259
dandovecfff212014-08-04 10:02:00 -07002260 LOOPER_END
2261}
2262
reed3cb38402015-02-06 08:36:15 -08002263void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002264 if (dr && !this->quickReject(dr->getBounds())) {
2265 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002266 }
2267}
2268
reed3cb38402015-02-06 08:36:15 -08002269void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002270 dr->draw(this);
2271}
2272
reed@android.com8a1c16f2008-12-17 15:59:43 +00002273//////////////////////////////////////////////////////////////////////////////
2274// These methods are NOT virtual, and therefore must call back into virtual
2275// methods, rather than actually drawing themselves.
2276//////////////////////////////////////////////////////////////////////////////
2277
2278void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002279 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002280 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002281 SkPaint paint;
2282
2283 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002284 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002285 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002286 }
2287 this->drawPaint(paint);
2288}
2289
reed@android.com845fdac2009-06-23 03:01:32 +00002290void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002291 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002292 SkPaint paint;
2293
2294 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002295 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002296 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002297 }
2298 this->drawPaint(paint);
2299}
2300
2301void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002302 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002303 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002304
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305 pt.set(x, y);
2306 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2307}
2308
2309void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002310 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002311 SkPoint pt;
2312 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002313
reed@android.com8a1c16f2008-12-17 15:59:43 +00002314 pt.set(x, y);
2315 paint.setColor(color);
2316 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2317}
2318
2319void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2320 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002321 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002322 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002323
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324 pts[0].set(x0, y0);
2325 pts[1].set(x1, y1);
2326 this->drawPoints(kLines_PointMode, 2, pts, paint);
2327}
2328
2329void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2330 SkScalar right, SkScalar bottom,
2331 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002332 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002333 SkRect r;
2334
2335 r.set(left, top, right, bottom);
2336 this->drawRect(r, paint);
2337}
2338
2339void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2340 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002341 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002342 if (radius < 0) {
2343 radius = 0;
2344 }
2345
2346 SkRect r;
2347 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002348 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002349}
2350
2351void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2352 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002353 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002354 if (rx > 0 && ry > 0) {
2355 if (paint.canComputeFastBounds()) {
2356 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002357 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002358 return;
2359 }
2360 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002361 SkRRect rrect;
2362 rrect.setRectXY(r, rx, ry);
2363 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002364 } else {
2365 this->drawRect(r, paint);
2366 }
2367}
2368
reed@android.com8a1c16f2008-12-17 15:59:43 +00002369void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2370 SkScalar sweepAngle, bool useCenter,
2371 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002372 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002373 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2374 this->drawOval(oval, paint);
2375 } else {
2376 SkPath path;
2377 if (useCenter) {
2378 path.moveTo(oval.centerX(), oval.centerY());
2379 }
2380 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2381 if (useCenter) {
2382 path.close();
2383 }
2384 this->drawPath(path, paint);
2385 }
2386}
2387
2388void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2389 const SkPath& path, SkScalar hOffset,
2390 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002391 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002392 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002393
reed@android.com8a1c16f2008-12-17 15:59:43 +00002394 matrix.setTranslate(hOffset, vOffset);
2395 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2396}
2397
reed@android.comf76bacf2009-05-13 14:00:33 +00002398///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002399void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002400 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002401 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002402 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002403 }
2404}
2405
reedd5fa1a42014-08-09 11:08:05 -07002406void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002407 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002408 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002409 if (matrix && matrix->isIdentity()) {
2410 matrix = NULL;
2411 }
2412 this->onDrawPicture(picture, matrix, paint);
2413 }
2414}
robertphillips9b14f262014-06-04 05:40:44 -07002415
reedd5fa1a42014-08-09 11:08:05 -07002416void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2417 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002418 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002419 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002420 // Canvas has to first give the device the opportunity to render
2421 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002422 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002423 return; // the device has rendered the entire picture
2424 }
2425 }
2426
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002427 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002428
robertphillipsc5ba71d2014-09-04 08:42:50 -07002429 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002430}
2431
reed@android.com8a1c16f2008-12-17 15:59:43 +00002432///////////////////////////////////////////////////////////////////////////////
2433///////////////////////////////////////////////////////////////////////////////
2434
2435SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002436 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002437
2438 SkASSERT(canvas);
2439
2440 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2441 fDone = !fImpl->next();
2442}
2443
2444SkCanvas::LayerIter::~LayerIter() {
2445 fImpl->~SkDrawIter();
2446}
2447
2448void SkCanvas::LayerIter::next() {
2449 fDone = !fImpl->next();
2450}
2451
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002452SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002453 return fImpl->getDevice();
2454}
2455
2456const SkMatrix& SkCanvas::LayerIter::matrix() const {
2457 return fImpl->getMatrix();
2458}
2459
2460const SkPaint& SkCanvas::LayerIter::paint() const {
2461 const SkPaint* paint = fImpl->getPaint();
2462 if (NULL == paint) {
2463 paint = &fDefaultPaint;
2464 }
2465 return *paint;
2466}
2467
2468const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2469int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2470int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002471
2472///////////////////////////////////////////////////////////////////////////////
2473
fmalitac3b589a2014-06-05 12:40:07 -07002474SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002475
2476///////////////////////////////////////////////////////////////////////////////
2477
2478static bool supported_for_raster_canvas(const SkImageInfo& info) {
2479 switch (info.alphaType()) {
2480 case kPremul_SkAlphaType:
2481 case kOpaque_SkAlphaType:
2482 break;
2483 default:
2484 return false;
2485 }
2486
2487 switch (info.colorType()) {
2488 case kAlpha_8_SkColorType:
2489 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002490 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002491 break;
2492 default:
2493 return false;
2494 }
2495
2496 return true;
2497}
2498
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002499SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2500 if (!supported_for_raster_canvas(info)) {
2501 return NULL;
2502 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002503
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002504 SkBitmap bitmap;
2505 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2506 return NULL;
2507 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002508 return SkNEW_ARGS(SkCanvas, (bitmap));
2509}
reedd5fa1a42014-08-09 11:08:05 -07002510
2511///////////////////////////////////////////////////////////////////////////////
2512
2513SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002514 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002515 : fCanvas(canvas)
2516 , fSaveCount(canvas->getSaveCount())
2517{
bsalomon49f085d2014-09-05 13:34:00 -07002518 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002519 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002520 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002521 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002522 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002523 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002524 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002525 canvas->save();
2526 }
mtklein6cfa73a2014-08-13 13:33:49 -07002527
bsalomon49f085d2014-09-05 13:34:00 -07002528 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002529 canvas->concat(*matrix);
2530 }
2531}
2532
2533SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2534 fCanvas->restoreToCount(fSaveCount);
2535}