blob: 11dc739f4c4dc6aa0509f8ba404a56fa246817e4 [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,
reed76033be2015-03-14 10:54:31 -0700302 SkCanvas::kFullLayer_SaveLayerStrategy);
reed@google.com8926b162012-03-23 15:36:36 +0000303 // we'll clear the imageFilter for the actual draws in next(), so
304 // it will only be applied during the restore().
305 fDoClearImageFilter = true;
306 }
307
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000308 if (SkDrawLooper* looper = paint.getLooper()) {
309 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
310 looper->contextSize());
311 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000312 fIsSimple = false;
313 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000314 fLooperContext = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000315 // can we be marked as simple?
316 fIsSimple = !fFilter && !fDoClearImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000317 }
piotaixrb5fae932014-09-24 13:03:30 -0700318
reed4a8126e2014-09-22 07:29:03 -0700319 uint32_t oldFlags = paint.getFlags();
320 fNewPaintFlags = filter_paint_flags(props, oldFlags);
321 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reed1b110d62015-03-08 18:47:13 -0700322 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700323 paint->setFlags(fNewPaintFlags);
324 fPaint = paint;
325 // if we're not simple, doNext() will take care of calling setFlags()
326 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000327 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000328
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 ~AutoDrawLooper() {
reed@google.com8926b162012-03-23 15:36:36 +0000330 if (fDoClearImageFilter) {
331 fCanvas->internalRestore();
332 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000333 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000335
reed@google.com4e2b3d32011-04-07 14:18:59 +0000336 const SkPaint& paint() const {
337 SkASSERT(fPaint);
338 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000340
reed@google.com129ec222012-05-15 13:24:09 +0000341 bool next(SkDrawFilter::Type drawType) {
342 if (fDone) {
343 return false;
344 } else if (fIsSimple) {
345 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000346 return !fPaint->nothingToDraw();
347 } else {
348 return this->doNext(drawType);
349 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000350 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000351
reed@android.com8a1c16f2008-12-17 15:59:43 +0000352private:
reed1b110d62015-03-08 18:47:13 -0700353 SkLazyPaint fLazyPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000354 SkCanvas* fCanvas;
355 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000356 SkDrawFilter* fFilter;
357 const SkPaint* fPaint;
358 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700359 uint32_t fNewPaintFlags;
reed@google.com8926b162012-03-23 15:36:36 +0000360 bool fDoClearImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000361 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000362 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000363 SkDrawLooper::Context* fLooperContext;
364 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000365
366 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367};
368
reed@google.com129ec222012-05-15 13:24:09 +0000369bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
reed@google.com632e1a22011-10-06 12:37:00 +0000370 fPaint = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000371 SkASSERT(!fIsSimple);
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000372 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000373
reed1b110d62015-03-08 18:47:13 -0700374 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700375 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000376
377 if (fDoClearImageFilter) {
378 paint->setImageFilter(NULL);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000379 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000380
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000381 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000382 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000383 return false;
384 }
385 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000386 if (!fFilter->filter(paint, drawType)) {
387 fDone = true;
388 return false;
389 }
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000390 if (NULL == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000391 // no looper means we only draw once
392 fDone = true;
393 }
394 }
395 fPaint = paint;
396
397 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000398 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000399 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000400 }
401
402 // call this after any possible paint modifiers
403 if (fPaint->nothingToDraw()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000404 fPaint = NULL;
405 return false;
406 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000407 return true;
408}
409
reed@android.com8a1c16f2008-12-17 15:59:43 +0000410////////// macros to place around the internal draw calls //////////////////
411
reed@google.com8926b162012-03-23 15:36:36 +0000412#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000413 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700414 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000415 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000416 SkDrawIter iter(this);
417
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000418#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000419 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700420 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000421 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000423
reed@google.com4e2b3d32011-04-07 14:18:59 +0000424#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000425
426////////////////////////////////////////////////////////////////////////////
427
reedd9544982014-09-09 18:46:22 -0700428SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
429 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
reed@google.comc0784db2013-12-13 21:16:12 +0000430 fCachedLocalClipBounds.setEmpty();
431 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000432 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000433 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700434 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800435 fSaveCount = 1;
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000436 fMetaData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437
438 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700439 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440
reed96e657d2015-03-10 17:30:07 -0700441 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, NULL, NULL, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443
reed@google.com97af1a62012-08-28 12:19:02 +0000444 fSurfaceBase = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000445
joshualittde358a92015-02-05 08:19:35 -0800446 fClipStack.reset(SkNEW(SkClipStack));
447
reedf92c8662014-08-18 08:02:43 -0700448 if (device) {
reedb2db8982014-11-13 12:41:02 -0800449 device->initForRootLayer(fProps.pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700450 if (device->forceConservativeRasterClip()) {
451 fConservativeRasterClip = true;
452 }
reedf92c8662014-08-18 08:02:43 -0700453 device->onAttachToCanvas(this);
454 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800455 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700456 }
457 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000458}
459
reed@google.comcde92112011-07-06 20:00:52 +0000460SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000461 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700462 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000463{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000464 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000465
reedd9544982014-09-09 18:46:22 -0700466 this->init(NULL, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000467}
468
reedd9544982014-09-09 18:46:22 -0700469static SkBitmap make_nopixels(int width, int height) {
470 SkBitmap bitmap;
471 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
472 return bitmap;
473}
474
475class SkNoPixelsBitmapDevice : public SkBitmapDevice {
476public:
reed78e27682014-11-19 08:04:34 -0800477 SkNoPixelsBitmapDevice(const SkIRect& bounds)
478 : INHERITED(make_nopixels(bounds.width(), bounds.height()))
479 {
480 this->setOrigin(bounds.x(), bounds.y());
481 }
reedd9544982014-09-09 18:46:22 -0700482
483private:
piotaixrb5fae932014-09-24 13:03:30 -0700484
reedd9544982014-09-09 18:46:22 -0700485 typedef SkBitmapDevice INHERITED;
486};
487
reed96a857e2015-01-25 10:33:58 -0800488SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000489 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800490 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000491{
492 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700493
reed78e27682014-11-19 08:04:34 -0800494 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
495 (SkIRect::MakeWH(width, height))), kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700496}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000497
reed78e27682014-11-19 08:04:34 -0800498SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700499 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700500 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700501{
502 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700503
reed78e27682014-11-19 08:04:34 -0800504 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds)), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700505}
506
reed4a8126e2014-09-22 07:29:03 -0700507SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700508 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700509 , fProps(SkSurfacePropsCopyOrDefault(props))
reedd9544982014-09-09 18:46:22 -0700510{
511 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700512
reedd9544982014-09-09 18:46:22 -0700513 this->init(device, flags);
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000514}
515
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000516SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000517 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700518 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000519{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000520 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700521
reedd9544982014-09-09 18:46:22 -0700522 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523}
524
reed4a8126e2014-09-22 07:29:03 -0700525SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700526 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700527 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700528{
529 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700530
reed4a8126e2014-09-22 07:29:03 -0700531 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
532 this->init(device, kDefault_InitFlags);
533}
reed29c857d2014-09-21 10:25:07 -0700534
reed4a8126e2014-09-22 07:29:03 -0700535SkCanvas::SkCanvas(const SkBitmap& bitmap)
536 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
537 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
538{
539 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700540
reed4a8126e2014-09-22 07:29:03 -0700541 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
542 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000543}
544
545SkCanvas::~SkCanvas() {
546 // free up the contents of our deque
547 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000548
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549 this->internalRestore(); // restore the last, since we're going away
550
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000551 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000552
reed@android.com8a1c16f2008-12-17 15:59:43 +0000553 dec_canvas();
554}
555
reed@android.com8a1c16f2008-12-17 15:59:43 +0000556SkDrawFilter* SkCanvas::getDrawFilter() const {
557 return fMCRec->fFilter;
558}
559
560SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
561 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
562 return filter;
563}
564
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000565SkMetaData& SkCanvas::getMetaData() {
566 // metadata users are rare, so we lazily allocate it. If that changes we
567 // can decide to just make it a field in the device (rather than a ptr)
568 if (NULL == fMetaData) {
569 fMetaData = new SkMetaData;
570 }
571 return *fMetaData;
572}
573
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574///////////////////////////////////////////////////////////////////////////////
575
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000576void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000577 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000578 if (device) {
579 device->flush();
580 }
581}
582
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000583SkISize SkCanvas::getTopLayerSize() const {
584 SkBaseDevice* d = this->getTopDevice();
585 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
586}
587
588SkIPoint SkCanvas::getTopLayerOrigin() const {
589 SkBaseDevice* d = this->getTopDevice();
590 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
591}
592
593SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000594 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000595 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
596}
597
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000598SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000599 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000600 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601 SkASSERT(rec && rec->fLayer);
602 return rec->fLayer->fDevice;
603}
604
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000605SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000606 if (updateMatrixClip) {
607 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
608 }
reed@google.com9266fed2011-03-30 00:18:03 +0000609 return fMCRec->fTopLayer->fDevice;
610}
611
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000612bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
613 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
614 return false;
615 }
616
617 bool weAllocated = false;
618 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700619 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000620 return false;
621 }
622 weAllocated = true;
623 }
624
625 SkBitmap bm(*bitmap);
626 bm.lockPixels();
627 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
628 return true;
629 }
630
631 if (weAllocated) {
632 bitmap->setPixelRef(NULL);
633 }
634 return false;
635}
reed@google.com51df9e32010-12-23 19:29:18 +0000636
bsalomon@google.comc6980972011-11-02 19:57:21 +0000637bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000638 SkIRect r = srcRect;
639 const SkISize size = this->getBaseLayerSize();
640 if (!r.intersect(0, 0, size.width(), size.height())) {
641 bitmap->reset();
642 return false;
643 }
644
reed84825042014-09-02 12:50:45 -0700645 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000646 // bitmap will already be reset.
647 return false;
648 }
649 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
650 bitmap->reset();
651 return false;
652 }
653 return true;
654}
655
reed96472de2014-12-10 09:53:42 -0800656bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000657 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000658 if (!device) {
659 return false;
660 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000661 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800662
reed96472de2014-12-10 09:53:42 -0800663 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
664 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000665 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000666 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000667
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000668 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800669 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000670}
671
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000672bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
673 if (bitmap.getTexture()) {
674 return false;
675 }
676 SkBitmap bm(bitmap);
677 bm.lockPixels();
678 if (bm.getPixels()) {
679 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
680 }
681 return false;
682}
683
684bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
685 int x, int y) {
686 switch (origInfo.colorType()) {
687 case kUnknown_SkColorType:
688 case kIndex_8_SkColorType:
689 return false;
690 default:
691 break;
692 }
693 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
694 return false;
695 }
696
697 const SkISize size = this->getBaseLayerSize();
698 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
699 if (!target.intersect(0, 0, size.width(), size.height())) {
700 return false;
701 }
702
703 SkBaseDevice* device = this->getDevice();
704 if (!device) {
705 return false;
706 }
707
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000708 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700709 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000710
711 // if x or y are negative, then we have to adjust pixels
712 if (x > 0) {
713 x = 0;
714 }
715 if (y > 0) {
716 y = 0;
717 }
718 // here x,y are either 0 or negative
719 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
720
reed4af35f32014-06-27 17:47:49 -0700721 // Tell our owning surface to bump its generation ID
722 this->predrawNotify();
723
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000724 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000725 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000726}
reed@google.com51df9e32010-12-23 19:29:18 +0000727
junov@google.com4370aed2012-01-18 16:21:08 +0000728SkCanvas* SkCanvas::canvasForDrawIter() {
729 return this;
730}
731
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732//////////////////////////////////////////////////////////////////////////////
733
reed@android.com8a1c16f2008-12-17 15:59:43 +0000734void SkCanvas::updateDeviceCMCache() {
735 if (fDeviceCMDirty) {
736 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700737 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000738 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000739
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740 if (NULL == layer->fNext) { // only one layer
joshualittde358a92015-02-05 08:19:35 -0800741 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000743 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000744 do {
joshualittde358a92015-02-05 08:19:35 -0800745 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746 } while ((layer = layer->fNext) != NULL);
747 }
748 fDeviceCMDirty = false;
749 }
750}
751
reed@android.com8a1c16f2008-12-17 15:59:43 +0000752///////////////////////////////////////////////////////////////////////////////
753
reed2ff1fce2014-12-11 07:07:37 -0800754void SkCanvas::checkForDeferredSave() {
755 if (fMCRec->fDeferredSaveCount > 0) {
756 fMCRec->fDeferredSaveCount -= 1;
757 this->doSave();
758 }
759}
760
reedf0090cb2014-11-26 08:55:51 -0800761int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800762#ifdef SK_DEBUG
763 int count = 0;
764 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
765 for (;;) {
766 const MCRec* rec = (const MCRec*)iter.next();
767 if (!rec) {
768 break;
769 }
770 count += 1 + rec->fDeferredSaveCount;
771 }
772 SkASSERT(count == fSaveCount);
773#endif
774 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800775}
776
777int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800778 fSaveCount += 1;
779 fMCRec->fDeferredSaveCount += 1;
780 return this->getSaveCount() - 1; // return our prev value
781}
782
783void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800784 this->willSave();
reed2ff1fce2014-12-11 07:07:37 -0800785 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800786}
787
788void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800789 if (fMCRec->fDeferredSaveCount > 0) {
790 SkASSERT(fSaveCount > 1);
791 fSaveCount -= 1;
792 fMCRec->fDeferredSaveCount -= 1;
793 } else {
794 // check for underflow
795 if (fMCStack.count() > 1) {
796 this->willRestore();
797 SkASSERT(fSaveCount > 1);
798 fSaveCount -= 1;
799 this->internalRestore();
800 this->didRestore();
801 }
reedf0090cb2014-11-26 08:55:51 -0800802 }
803}
804
805void SkCanvas::restoreToCount(int count) {
806 // sanity check
807 if (count < 1) {
808 count = 1;
809 }
mtkleinf0f14112014-12-12 08:46:25 -0800810
reedf0090cb2014-11-26 08:55:51 -0800811 int n = this->getSaveCount() - count;
812 for (int i = 0; i < n; ++i) {
813 this->restore();
814 }
815}
816
reed2ff1fce2014-12-11 07:07:37 -0800817void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000818 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700819 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000820 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000821
joshualittde358a92015-02-05 08:19:35 -0800822 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823}
824
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000826#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000828#else
829 return true;
830#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831}
832
junov@chromium.orga907ac32012-02-24 21:54:07 +0000833bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700834 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000835 SkIRect clipBounds;
836 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000837 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000838 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000839
reed96e657d2015-03-10 17:30:07 -0700840 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
841
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000842 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700843 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000844 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000845 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700846 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000847 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000848
reed96e657d2015-03-10 17:30:07 -0700849 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850 r.roundOut(&ir);
851 // early exit if the layer's bounds are clipped out
852 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000853 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700854 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700855 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000856 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000857 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000858 }
859 } else { // no user bounds, so just use the clip
860 ir = clipBounds;
861 }
reed180aec42015-03-11 10:39:04 -0700862 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000863
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000864 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -0700865 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -0700866 fCachedLocalClipBoundsDirty = true;
reed180aec42015-03-11 10:39:04 -0700867 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
868 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000869 }
870
871 if (intersection) {
872 *intersection = ir;
873 }
874 return true;
875}
876
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000877int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800878 if (gIgnoreSaveLayerBounds) {
879 bounds = NULL;
880 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000881 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reed2ff1fce2014-12-11 07:07:37 -0800882 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700883 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800884 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000885}
886
reed2ff1fce2014-12-11 07:07:37 -0800887int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800888 if (gIgnoreSaveLayerBounds) {
889 bounds = NULL;
890 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000891 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reed2ff1fce2014-12-11 07:07:37 -0800892 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700893 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800894 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000895}
896
reed2ff1fce2014-12-11 07:07:37 -0800897void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -0700898 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000899#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000900 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000901#endif
902
junov@chromium.orga907ac32012-02-24 21:54:07 +0000903 // do this before we create the layer. We don't call the public save() since
904 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -0800905 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000906
907 fDeviceCMDirty = true;
908
909 SkIRect ir;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000910 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -0800911 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000912 }
913
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000914 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
915 // the clipRectBounds() call above?
916 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -0800917 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000918 }
919
reed76033be2015-03-14 10:54:31 -0700920 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
921 if (isOpaque && paint) {
922 // TODO: perhaps add a query to filters so we might preserve opaqueness...
923 if (paint->getImageFilter() || paint->getColorFilter()) {
924 isOpaque = false;
reed@google.comb55deeb2012-01-06 14:43:09 +0000925 }
926 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000927 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
928 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000929
reedb2db8982014-11-13 12:41:02 -0800930 SkBaseDevice* device = this->getTopDevice();
931 if (NULL == device) {
932 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800933 return;
reed@google.com76dd2772012-01-05 21:15:07 +0000934 }
reedb2db8982014-11-13 12:41:02 -0800935
reed76033be2015-03-14 10:54:31 -0700936 SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
937#if 1
938 // this seems needed for current GMs, but makes us draw slower on the GPU
939 // Related to https://code.google.com/p/skia/issues/detail?id=3519 ?
940 //
reedb2db8982014-11-13 12:41:02 -0800941 if (paint && paint->getImageFilter()) {
reed76033be2015-03-14 10:54:31 -0700942 usage = SkBaseDevice::kPossible_TileUsage;
reedb2db8982014-11-13 12:41:02 -0800943 }
reed76033be2015-03-14 10:54:31 -0700944#endif
945 device = device->onCreateDevice(SkBaseDevice::CreateInfo(info, usage, fProps.pixelGeometry()),
946 paint);
bungeman@google.come25c6842011-08-17 14:53:54 +0000947 if (NULL == device) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800948 SkErrorInternals::SetError( kInternalError_SkError,
949 "Unable to create device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800950 return;
bungeman@google.come25c6842011-08-17 14:53:54 +0000951 }
bsalomon@google.come97f0852011-06-17 13:10:25 +0000952
reed@google.com6f8f2922011-03-04 22:27:10 +0000953 device->setOrigin(ir.fLeft, ir.fTop);
reed96e657d2015-03-10 17:30:07 -0700954 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955 device->unref();
956
957 layer->fNext = fMCRec->fTopLayer;
958 fMCRec->fLayer = layer;
959 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960}
961
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000962int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
963 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
964}
965
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
967 SaveFlags flags) {
968 if (0xFF == alpha) {
969 return this->saveLayer(bounds, NULL, flags);
970 } else {
971 SkPaint tmpPaint;
972 tmpPaint.setAlpha(alpha);
973 return this->saveLayer(bounds, &tmpPaint, flags);
974 }
975}
976
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977void SkCanvas::internalRestore() {
978 SkASSERT(fMCStack.count() != 0);
979
980 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +0000981 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982
joshualittde358a92015-02-05 08:19:35 -0800983 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +0000984
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000985 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000986 DeviceCM* layer = fMCRec->fLayer; // may be null
987 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
988 fMCRec->fLayer = NULL;
989
990 // now do the normal restore()
991 fMCRec->~MCRec(); // balanced in save()
992 fMCStack.pop_back();
993 fMCRec = (MCRec*)fMCStack.back();
994
995 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
996 since if we're being recorded, we don't want to record this (the
997 recorder will have already recorded the restore).
998 */
bsalomon49f085d2014-09-05 13:34:00 -0700999 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001000 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001001 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001002 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1003 layer->fPaint);
1004 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001005 fDeviceCMDirty = true;
1006 }
1007 SkDELETE(layer);
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001008 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001009}
1010
reed4a8126e2014-09-22 07:29:03 -07001011SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1012 if (NULL == props) {
1013 props = &fProps;
1014 }
1015 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001016}
1017
reed4a8126e2014-09-22 07:29:03 -07001018SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001019 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001020 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001021}
1022
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001023SkImageInfo SkCanvas::imageInfo() const {
1024 SkBaseDevice* dev = this->getDevice();
1025 if (dev) {
1026 return dev->imageInfo();
1027 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001028 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001029 }
1030}
1031
1032const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1033 return this->onPeekPixels(info, rowBytes);
1034}
1035
1036const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1037 SkBaseDevice* dev = this->getDevice();
1038 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1039}
1040
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001041void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1042 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1043 if (pixels && origin) {
1044 *origin = this->getTopDevice(false)->getOrigin();
1045 }
1046 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001047}
1048
1049void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1050 SkBaseDevice* dev = this->getTopDevice();
1051 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1052}
1053
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001054SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1055 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1056 if (NULL == fAddr) {
1057 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001058 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001059 return; // failure, fAddr is NULL
1060 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001061 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1062 return; // failure, fAddr is NULL
1063 }
1064 fAddr = fBitmap.getPixels();
1065 fRowBytes = fBitmap.rowBytes();
1066 }
1067 SkASSERT(fAddr); // success
1068}
1069
1070bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1071 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001072 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001073 } else {
1074 bitmap->reset();
1075 return false;
1076 }
1077}
1078
reed@android.com8a1c16f2008-12-17 15:59:43 +00001079/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001080void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001081 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001082 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001083 return;
1084 }
1085
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001086 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001087 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001088 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001090
1091 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001092
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001093 SkRect storage;
1094 const SkRect* bounds = NULL;
1095 if (paint && paint->canComputeFastBounds()) {
1096 bitmap.getBounds(&storage);
1097 matrix.mapRect(&storage);
1098 bounds = &paint->computeFastBounds(storage, &storage);
1099 }
1100
1101 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001102
1103 while (iter.next()) {
1104 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1105 }
1106
1107 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001108}
1109
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001110void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed@google.com8926b162012-03-23 15:36:36 +00001111 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001112 SkPaint tmp;
1113 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001114 paint = &tmp;
1115 }
reed@google.com4b226022011-01-11 18:32:13 +00001116
reed@google.com8926b162012-03-23 15:36:36 +00001117 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001118 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001119 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001120 paint = &looper.paint();
1121 SkImageFilter* filter = paint->getImageFilter();
1122 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001123 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001124 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001125 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001126 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001127 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001128 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001129 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001130 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001131 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001132 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001133 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001134 SkPaint tmpUnfiltered(*paint);
1135 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001136 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1137 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001138 }
1139 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001140 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001141 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001142 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001143 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001144}
1145
reed41af9662015-01-05 07:49:08 -08001146void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001147 if (gTreatSpriteAsBitmap) {
1148 this->save();
1149 this->resetMatrix();
1150 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1151 this->restore();
1152 return;
1153 }
1154
danakj9881d632014-11-26 12:41:06 -08001155 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001156 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001157 return;
1158 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001159 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001160
reed@google.com8926b162012-03-23 15:36:36 +00001161 SkPaint tmp;
1162 if (NULL == paint) {
1163 paint = &tmp;
1164 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001165
reed@google.com8926b162012-03-23 15:36:36 +00001166 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001167
reed@google.com8926b162012-03-23 15:36:36 +00001168 while (iter.next()) {
1169 paint = &looper.paint();
1170 SkImageFilter* filter = paint->getImageFilter();
1171 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1172 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001173 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001174 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001175 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001176 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001177 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001178 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001179 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001180 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001181 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001182 SkPaint tmpUnfiltered(*paint);
1183 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001184 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001185 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001186 }
1187 } else {
1188 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1189 }
1190 }
1191 LOOPER_END
1192}
1193
reed@android.com8a1c16f2008-12-17 15:59:43 +00001194/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001195void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001196 SkMatrix m;
1197 m.setTranslate(dx, dy);
1198 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001199}
1200
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001201void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001202 SkMatrix m;
1203 m.setScale(sx, sy);
1204 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001205}
1206
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001207void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001208 SkMatrix m;
1209 m.setRotate(degrees);
1210 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001211}
1212
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001213void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001214 SkMatrix m;
1215 m.setSkew(sx, sy);
1216 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001217}
1218
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001219void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001220 if (matrix.isIdentity()) {
1221 return;
1222 }
1223
reed2ff1fce2014-12-11 07:07:37 -08001224 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001225 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001226 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001227 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001228
1229 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001230}
1231
reed@android.com8a1c16f2008-12-17 15:59:43 +00001232void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001233 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001234 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001235 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001236 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001237 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001238}
1239
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240void SkCanvas::resetMatrix() {
1241 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001242
reed@android.com8a1c16f2008-12-17 15:59:43 +00001243 matrix.reset();
1244 this->setMatrix(matrix);
1245}
1246
1247//////////////////////////////////////////////////////////////////////////////
1248
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001249void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001250 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001251 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1252 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001253}
1254
1255void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001256#ifdef SK_ENABLE_CLIP_QUICKREJECT
1257 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001258 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001259 return false;
1260 }
1261
reed@google.com3b3e8952012-08-16 20:53:31 +00001262 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001263 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001264 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001265
1266 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001267 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001268 }
1269 }
1270#endif
1271
reed@google.com5c3d1472011-02-22 19:12:23 +00001272 AutoValidateClip avc(this);
1273
reed@android.com8a1c16f2008-12-17 15:59:43 +00001274 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001275 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001276 if (!fAllowSoftClip) {
1277 edgeStyle = kHard_ClipEdgeStyle;
1278 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001279
reed1f836ee2014-07-07 07:49:34 -07001280 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001281 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001282 // the matrix. This means we don't have to a) make a path, and b) tell
1283 // the region code to scan-convert the path, only to discover that it
1284 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001286
reed1f836ee2014-07-07 07:49:34 -07001287 fMCRec->fMatrix.mapRect(&r, rect);
joshualittde358a92015-02-05 08:19:35 -08001288 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001289 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001291 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001292 // and clip against that, since it can handle any matrix. However, to
1293 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1294 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 SkPath path;
1296
1297 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001298 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299 }
1300}
1301
reed73e714e2014-09-04 09:02:23 -07001302static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1303 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001304 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001305}
1306
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001307void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001308 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001309 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001310 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001311 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1312 } else {
1313 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001314 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001315}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001316
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001317void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001318 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001319 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001320 AutoValidateClip avc(this);
1321
1322 fDeviceCMDirty = true;
1323 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001324 if (!fAllowSoftClip) {
1325 edgeStyle = kHard_ClipEdgeStyle;
1326 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001327
joshualittde358a92015-02-05 08:19:35 -08001328 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001329
1330 SkPath devPath;
1331 devPath.addRRect(transformedRRect);
1332
reed73e714e2014-09-04 09:02:23 -07001333 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001334 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001335 }
1336
1337 SkPath path;
1338 path.addRRect(rrect);
1339 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001340 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001341}
1342
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001343void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001344 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001345 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1346 SkRect r;
1347 if (!path.isInverseFillType() && path.isRect(&r)) {
1348 this->onClipRect(r, op, edgeStyle);
1349 } else {
1350 this->onClipPath(path, op, edgeStyle);
1351 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001352}
1353
1354void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001355#ifdef SK_ENABLE_CLIP_QUICKREJECT
1356 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001357 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001358 return false;
1359 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001360
reed@google.com3b3e8952012-08-16 20:53:31 +00001361 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001362 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001363 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001364
reed@google.comda17f752012-08-16 18:27:05 +00001365 fClipStack.clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001366 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001367 }
1368 }
1369#endif
1370
reed@google.com5c3d1472011-02-22 19:12:23 +00001371 AutoValidateClip avc(this);
1372
reed@android.com8a1c16f2008-12-17 15:59:43 +00001373 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001374 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001375 if (!fAllowSoftClip) {
1376 edgeStyle = kHard_ClipEdgeStyle;
1377 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001378
1379 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001380 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381
reed@google.comfe701122011-11-08 19:41:23 +00001382 // Check if the transfomation, or the original path itself
1383 // made us empty. Note this can also happen if we contained NaN
1384 // values. computing the bounds detects this, and will set our
1385 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1386 if (devPath.getBounds().isEmpty()) {
1387 // resetting the path will remove any NaN or other wanky values
1388 // that might upset our scan converter.
1389 devPath.reset();
1390 }
1391
reed@google.com5c3d1472011-02-22 19:12:23 +00001392 // if we called path.swap() we could avoid a deep copy of this path
joshualittde358a92015-02-05 08:19:35 -08001393 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001394
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001395 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001396 bool clipIsAA = getClipStack()->asPath(&devPath);
1397 if (clipIsAA) {
1398 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001399 }
fmalita1a481fe2015-02-04 07:39:34 -08001400
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001401 op = SkRegion::kReplace_Op;
1402 }
1403
reed73e714e2014-09-04 09:02:23 -07001404 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001405}
1406
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001407void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001408 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001409 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001410}
1411
1412void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001413 AutoValidateClip avc(this);
1414
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001416 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001417
reed@google.com5c3d1472011-02-22 19:12:23 +00001418 // todo: signal fClipStack that we have a region, and therefore (I guess)
1419 // we have to ignore it, and use the region directly?
joshualittde358a92015-02-05 08:19:35 -08001420 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001421
reed1f836ee2014-07-07 07:49:34 -07001422 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423}
1424
reed@google.com819c9212011-02-23 18:56:55 +00001425#ifdef SK_DEBUG
1426void SkCanvas::validateClip() const {
1427 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001428 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001429 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001430 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001431 return;
1432 }
1433
reed@google.com819c9212011-02-23 18:56:55 +00001434 SkIRect ir;
1435 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001436 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001437
joshualittde358a92015-02-05 08:19:35 -08001438 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001439 const SkClipStack::Element* element;
1440 while ((element = iter.next()) != NULL) {
1441 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001442 case SkClipStack::Element::kRect_Type:
1443 element->getRect().round(&ir);
1444 tmpClip.op(ir, element->getOp());
1445 break;
1446 case SkClipStack::Element::kEmpty_Type:
1447 tmpClip.setEmpty();
1448 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001449 default: {
1450 SkPath path;
1451 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001452 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001453 break;
1454 }
reed@google.com819c9212011-02-23 18:56:55 +00001455 }
1456 }
reed@google.com819c9212011-02-23 18:56:55 +00001457}
1458#endif
1459
reed@google.com90c07ea2012-04-13 13:50:27 +00001460void SkCanvas::replayClips(ClipVisitor* visitor) const {
joshualittde358a92015-02-05 08:19:35 -08001461 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001462 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001463
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001464 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001465 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001466 }
1467}
1468
reed@google.com5c3d1472011-02-22 19:12:23 +00001469///////////////////////////////////////////////////////////////////////////////
1470
reed@google.com754de5f2014-02-24 19:38:20 +00001471bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001472 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001473}
1474
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001475bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001476 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001477}
1478
reed@google.com3b3e8952012-08-16 20:53:31 +00001479bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001480 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001481 return true;
1482
reed1f836ee2014-07-07 07:49:34 -07001483 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001484 return true;
1485 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001486
reed1f836ee2014-07-07 07:49:34 -07001487 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001488 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001489 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001490 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001491 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001492 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001493
reed@android.coma380ae42009-07-21 01:17:02 +00001494 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001495 // TODO: should we use | instead, or compare all 4 at once?
1496 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001497 return true;
1498 }
reed@google.comc0784db2013-12-13 21:16:12 +00001499 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001500 return true;
1501 }
1502 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001504}
1505
reed@google.com3b3e8952012-08-16 20:53:31 +00001506bool SkCanvas::quickReject(const SkPath& path) const {
1507 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508}
1509
reed@google.com3b3e8952012-08-16 20:53:31 +00001510bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001511 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001512 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001513 return false;
1514 }
1515
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001516 SkMatrix inverse;
1517 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001518 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001519 if (bounds) {
1520 bounds->setEmpty();
1521 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001522 return false;
1523 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001524
bsalomon49f085d2014-09-05 13:34:00 -07001525 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001526 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001527 // adjust it outwards in case we are antialiasing
1528 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001529
reed@google.com8f4d2302013-12-17 16:44:46 +00001530 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1531 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001532 inverse.mapRect(bounds, r);
1533 }
1534 return true;
1535}
1536
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001537bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001538 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001539 if (clip.isEmpty()) {
1540 if (bounds) {
1541 bounds->setEmpty();
1542 }
1543 return false;
1544 }
1545
bsalomon49f085d2014-09-05 13:34:00 -07001546 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001547 *bounds = clip.getBounds();
1548 }
1549 return true;
1550}
1551
reed@android.com8a1c16f2008-12-17 15:59:43 +00001552const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001553 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001554}
1555
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001556const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001557 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001558}
1559
reed@google.com9c135db2014-03-12 18:28:35 +00001560GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1561 SkBaseDevice* dev = this->getTopDevice();
1562 return dev ? dev->accessRenderTarget() : NULL;
1563}
1564
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001565GrContext* SkCanvas::getGrContext() {
1566#if SK_SUPPORT_GPU
1567 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001568 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001569 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001570 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001571 return renderTarget->getContext();
1572 }
1573 }
1574#endif
1575
1576 return NULL;
1577
1578}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001579
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001580void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1581 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001582 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001583 if (outer.isEmpty()) {
1584 return;
1585 }
1586 if (inner.isEmpty()) {
1587 this->drawRRect(outer, paint);
1588 return;
1589 }
1590
1591 // We don't have this method (yet), but technically this is what we should
1592 // be able to assert...
1593 // SkASSERT(outer.contains(inner));
1594 //
1595 // For now at least check for containment of bounds
1596 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1597
1598 this->onDrawDRRect(outer, inner, paint);
1599}
1600
reed41af9662015-01-05 07:49:08 -08001601// These need to stop being virtual -- clients need to override the onDraw... versions
1602
1603void SkCanvas::drawPaint(const SkPaint& paint) {
1604 this->onDrawPaint(paint);
1605}
1606
1607void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1608 this->onDrawRect(r, paint);
1609}
1610
1611void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1612 this->onDrawOval(r, paint);
1613}
1614
1615void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1616 this->onDrawRRect(rrect, paint);
1617}
1618
1619void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1620 this->onDrawPoints(mode, count, pts, paint);
1621}
1622
1623void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1624 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1625 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1626 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1627 indices, indexCount, paint);
1628}
1629
1630void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1631 this->onDrawPath(path, paint);
1632}
1633
1634void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1635 this->onDrawImage(image, dx, dy, paint);
1636}
1637
1638void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1639 const SkPaint* paint) {
1640 this->onDrawImageRect(image, src, dst, paint);
1641}
1642
1643void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1644 this->onDrawBitmap(bitmap, dx, dy, paint);
1645}
1646
1647void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1648 const SkPaint* paint, DrawBitmapRectFlags flags) {
1649 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1650}
1651
1652void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1653 const SkPaint* paint) {
1654 this->onDrawBitmapNine(bitmap, center, dst, paint);
1655}
1656
1657void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
1658 this->onDrawSprite(bitmap, left, top, paint);
1659}
1660
reed@android.com8a1c16f2008-12-17 15:59:43 +00001661//////////////////////////////////////////////////////////////////////////////
1662// These are the virtual drawing methods
1663//////////////////////////////////////////////////////////////////////////////
1664
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001665void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001666 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001667 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1668 }
1669}
1670
reed41af9662015-01-05 07:49:08 -08001671void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001672 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001673 this->internalDrawPaint(paint);
1674}
1675
1676void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001677 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001678
1679 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001680 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681 }
1682
reed@google.com4e2b3d32011-04-07 14:18:59 +00001683 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001684}
1685
reed41af9662015-01-05 07:49:08 -08001686void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1687 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001688 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001689 if ((long)count <= 0) {
1690 return;
1691 }
1692
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001693 SkRect r, storage;
1694 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001695 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001696 // special-case 2 points (common for drawing a single line)
1697 if (2 == count) {
1698 r.set(pts[0], pts[1]);
1699 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001700 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001701 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001702 bounds = &paint.computeFastStrokeBounds(r, &storage);
1703 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001704 return;
1705 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001706 }
reed@google.coma584aed2012-05-16 14:06:02 +00001707
reed@android.com8a1c16f2008-12-17 15:59:43 +00001708 SkASSERT(pts != NULL);
1709
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001710 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001711
reed@android.com8a1c16f2008-12-17 15:59:43 +00001712 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001713 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001714 }
reed@google.com4b226022011-01-11 18:32:13 +00001715
reed@google.com4e2b3d32011-04-07 14:18:59 +00001716 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001717}
1718
reed41af9662015-01-05 07:49:08 -08001719void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001720 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001721 SkRect storage;
1722 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001723 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001724 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1725 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1726 SkRect tmp(r);
1727 tmp.sort();
1728
1729 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001730 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001731 return;
1732 }
1733 }
reed@google.com4b226022011-01-11 18:32:13 +00001734
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001735 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001736
1737 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001738 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001739 }
1740
reed@google.com4e2b3d32011-04-07 14:18:59 +00001741 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001742}
1743
reed41af9662015-01-05 07:49:08 -08001744void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001745 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001746 SkRect storage;
1747 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001748 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001749 bounds = &paint.computeFastBounds(oval, &storage);
1750 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001751 return;
1752 }
1753 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001754
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001755 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001756
1757 while (iter.next()) {
1758 iter.fDevice->drawOval(iter, oval, looper.paint());
1759 }
1760
1761 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001762}
1763
reed41af9662015-01-05 07:49:08 -08001764void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001765 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001766 SkRect storage;
1767 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001768 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001769 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1770 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001771 return;
1772 }
1773 }
1774
1775 if (rrect.isRect()) {
1776 // call the non-virtual version
1777 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001778 return;
1779 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001780 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001781 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1782 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001783 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001784
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001785 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001786
1787 while (iter.next()) {
1788 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1789 }
1790
1791 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001792}
1793
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001794void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1795 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001796 SkRect storage;
1797 const SkRect* bounds = NULL;
1798 if (paint.canComputeFastBounds()) {
1799 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1800 if (this->quickReject(*bounds)) {
1801 return;
1802 }
1803 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001804
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001805 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001806
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001807 while (iter.next()) {
1808 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1809 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001810
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001811 LOOPER_END
1812}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001813
reed41af9662015-01-05 07:49:08 -08001814void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001815 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001816 if (!path.isFinite()) {
1817 return;
1818 }
1819
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001820 SkRect storage;
1821 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001822 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001823 const SkRect& pathBounds = path.getBounds();
1824 bounds = &paint.computeFastBounds(pathBounds, &storage);
1825 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001826 return;
1827 }
1828 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001829
1830 const SkRect& r = path.getBounds();
1831 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001832 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001833 this->internalDrawPaint(paint);
1834 }
1835 return;
1836 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001837
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001838 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001839
1840 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001841 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001842 }
1843
reed@google.com4e2b3d32011-04-07 14:18:59 +00001844 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001845}
1846
kkinnunena9baa652015-03-05 06:33:54 -08001847void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001848 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
kkinnunena9baa652015-03-05 06:33:54 -08001849 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001850}
1851
reed41af9662015-01-05 07:49:08 -08001852void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1853 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001854 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
kkinnunena9baa652015-03-05 06:33:54 -08001855 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001856}
1857
reed41af9662015-01-05 07:49:08 -08001858void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001859 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001860 SkDEBUGCODE(bitmap.validate();)
1861
reed@google.com3d608122011-11-21 15:16:16 +00001862 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001863 SkRect bounds = {
1864 x, y,
1865 x + SkIntToScalar(bitmap.width()),
1866 y + SkIntToScalar(bitmap.height())
1867 };
1868 if (paint) {
1869 (void)paint->computeFastBounds(bounds, &bounds);
1870 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001871 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001872 return;
1873 }
1874 }
reed@google.com4b226022011-01-11 18:32:13 +00001875
reed@android.com8a1c16f2008-12-17 15:59:43 +00001876 SkMatrix matrix;
1877 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001878 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001879}
1880
reed@google.com9987ec32011-09-07 11:57:52 +00001881// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00001882void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001883 const SkRect& dst, const SkPaint* paint,
1884 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001885 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001886 return;
1887 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001888
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001889 SkRect storage;
1890 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00001891 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001892 if (paint) {
1893 bounds = &paint->computeFastBounds(dst, &storage);
1894 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001895 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001896 return;
1897 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001898 }
reed@google.com3d608122011-11-21 15:16:16 +00001899
reed@google.com33535f32012-09-25 15:37:50 +00001900 SkLazyPaint lazy;
1901 if (NULL == paint) {
1902 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001903 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001904
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001905 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001906
reed@google.com33535f32012-09-25 15:37:50 +00001907 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001908 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00001909 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001910
reed@google.com33535f32012-09-25 15:37:50 +00001911 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001912}
1913
reed41af9662015-01-05 07:49:08 -08001914void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1915 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08001916 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00001917 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001918 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00001919}
1920
reed@google.com9987ec32011-09-07 11:57:52 +00001921void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1922 const SkIRect& center, const SkRect& dst,
1923 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001924 if (bitmap.drawsNothing()) {
1925 return;
1926 }
reed@google.com3d608122011-11-21 15:16:16 +00001927 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00001928 SkRect storage;
1929 const SkRect* bounds = &dst;
1930 if (paint) {
1931 bounds = &paint->computeFastBounds(dst, &storage);
1932 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001933 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001934 return;
1935 }
1936 }
1937
reed@google.com9987ec32011-09-07 11:57:52 +00001938 const int32_t w = bitmap.width();
1939 const int32_t h = bitmap.height();
1940
1941 SkIRect c = center;
1942 // pin center to the bounds of the bitmap
1943 c.fLeft = SkMax32(0, center.fLeft);
1944 c.fTop = SkMax32(0, center.fTop);
1945 c.fRight = SkPin32(center.fRight, c.fLeft, w);
1946 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1947
reed@google.com71121732012-09-18 15:14:33 +00001948 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001949 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00001950 };
1951 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001952 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00001953 };
reed@google.com9987ec32011-09-07 11:57:52 +00001954 SkScalar dstX[4] = {
1955 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
1956 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
1957 };
1958 SkScalar dstY[4] = {
1959 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
1960 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
1961 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001962
reed@google.com9987ec32011-09-07 11:57:52 +00001963 if (dstX[1] > dstX[2]) {
1964 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
1965 dstX[2] = dstX[1];
1966 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001967
reed@google.com9987ec32011-09-07 11:57:52 +00001968 if (dstY[1] > dstY[2]) {
1969 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
1970 dstY[2] = dstY[1];
1971 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001972
reed@google.com9987ec32011-09-07 11:57:52 +00001973 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00001974 SkRect s, d;
1975
reed@google.com9987ec32011-09-07 11:57:52 +00001976 s.fTop = srcY[y];
1977 s.fBottom = srcY[y+1];
1978 d.fTop = dstY[y];
1979 d.fBottom = dstY[y+1];
1980 for (int x = 0; x < 3; x++) {
1981 s.fLeft = srcX[x];
1982 s.fRight = srcX[x+1];
1983 d.fLeft = dstX[x];
1984 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001985 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00001986 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00001987 }
1988 }
1989}
1990
reed41af9662015-01-05 07:49:08 -08001991void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1992 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001993 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00001994 SkDEBUGCODE(bitmap.validate();)
1995
1996 // Need a device entry-point, so gpu can use a mesh
1997 this->internalDrawBitmapNine(bitmap, center, dst, paint);
1998}
1999
reed@google.comf67e4cf2011-03-15 20:56:58 +00002000class SkDeviceFilteredPaint {
2001public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002002 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002003 uint32_t filteredFlags = device->filterTextFlags(paint);
2004 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002005 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002006 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002007 fPaint = newPaint;
2008 } else {
2009 fPaint = &paint;
2010 }
2011 }
2012
reed@google.comf67e4cf2011-03-15 20:56:58 +00002013 const SkPaint& paint() const { return *fPaint; }
2014
2015private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002016 const SkPaint* fPaint;
2017 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002018};
2019
bungeman@google.com52c748b2011-08-22 21:30:43 +00002020void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2021 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002022 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002023 draw.fDevice->drawRect(draw, r, paint);
2024 } else {
2025 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002026 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002027 draw.fDevice->drawRect(draw, r, p);
2028 }
2029}
2030
2031void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2032 const char text[], size_t byteLength,
2033 SkScalar x, SkScalar y) {
2034 SkASSERT(byteLength == 0 || text != NULL);
2035
2036 // nothing to draw
2037 if (text == NULL || byteLength == 0 ||
2038 draw.fClip->isEmpty() ||
2039 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2040 return;
2041 }
2042
2043 SkScalar width = 0;
2044 SkPoint start;
2045
2046 start.set(0, 0); // to avoid warning
2047 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2048 SkPaint::kStrikeThruText_Flag)) {
2049 width = paint.measureText(text, byteLength);
2050
2051 SkScalar offsetX = 0;
2052 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2053 offsetX = SkScalarHalf(width);
2054 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2055 offsetX = width;
2056 }
2057 start.set(x - offsetX, y);
2058 }
2059
2060 if (0 == width) {
2061 return;
2062 }
2063
2064 uint32_t flags = paint.getFlags();
2065
2066 if (flags & (SkPaint::kUnderlineText_Flag |
2067 SkPaint::kStrikeThruText_Flag)) {
2068 SkScalar textSize = paint.getTextSize();
2069 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2070 SkRect r;
2071
2072 r.fLeft = start.fX;
2073 r.fRight = start.fX + width;
2074
2075 if (flags & SkPaint::kUnderlineText_Flag) {
2076 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2077 start.fY);
2078 r.fTop = offset;
2079 r.fBottom = offset + height;
2080 DrawRect(draw, paint, r, textSize);
2081 }
2082 if (flags & SkPaint::kStrikeThruText_Flag) {
2083 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2084 start.fY);
2085 r.fTop = offset;
2086 r.fBottom = offset + height;
2087 DrawRect(draw, paint, r, textSize);
2088 }
2089 }
2090}
2091
reed@google.come0d9ce82014-04-23 04:00:17 +00002092void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2093 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002094 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002095
2096 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002097 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002098 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002099 DrawTextDecorations(iter, dfp.paint(),
2100 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002101 }
2102
reed@google.com4e2b3d32011-04-07 14:18:59 +00002103 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002104}
2105
reed@google.come0d9ce82014-04-23 04:00:17 +00002106void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2107 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002108 SkPoint textOffset = SkPoint::Make(0, 0);
2109
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002110 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002111
reed@android.com8a1c16f2008-12-17 15:59:43 +00002112 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002113 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002114 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002115 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002116 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002117
reed@google.com4e2b3d32011-04-07 14:18:59 +00002118 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002119}
2120
reed@google.come0d9ce82014-04-23 04:00:17 +00002121void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2122 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002123
2124 SkPoint textOffset = SkPoint::Make(0, constY);
2125
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002126 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002127
reed@android.com8a1c16f2008-12-17 15:59:43 +00002128 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002129 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002130 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002131 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002132 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002133
reed@google.com4e2b3d32011-04-07 14:18:59 +00002134 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002135}
2136
reed@google.come0d9ce82014-04-23 04:00:17 +00002137void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2138 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002139 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002140
reed@android.com8a1c16f2008-12-17 15:59:43 +00002141 while (iter.next()) {
2142 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002143 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002144 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002145
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002146 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002147}
2148
fmalita00d5c2c2014-08-21 08:53:26 -07002149void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2150 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002151
fmalita85d5eb92015-03-04 11:20:12 -08002152 SkRect storage;
2153 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002154 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002155 storage = blob->bounds().makeOffset(x, y);
2156 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002157
fmalita85d5eb92015-03-04 11:20:12 -08002158 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002159 return;
2160 }
2161 }
2162
fmalita024f9962015-03-03 19:08:17 -08002163 // We cannot filter in the looper as we normally do, because the paint is
2164 // incomplete at this point (text-related attributes are embedded within blob run paints).
2165 SkDrawFilter* drawFilter = fMCRec->fFilter;
2166 fMCRec->fFilter = NULL;
2167
fmalita85d5eb92015-03-04 11:20:12 -08002168 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002169
fmalitaaa1b9122014-08-28 14:32:24 -07002170 while (iter.next()) {
2171 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002172 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002173 }
2174
fmalitaaa1b9122014-08-28 14:32:24 -07002175 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002176
2177 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002178}
2179
reed@google.come0d9ce82014-04-23 04:00:17 +00002180// These will become non-virtual, so they always call the (virtual) onDraw... method
2181void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2182 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002183 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002184 this->onDrawText(text, byteLength, x, y, paint);
2185}
2186void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2187 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002188 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002189 this->onDrawPosText(text, byteLength, pos, paint);
2190}
2191void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2192 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002193 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002194 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2195}
2196void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2197 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002198 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002199 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2200}
fmalita00d5c2c2014-08-21 08:53:26 -07002201void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2202 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002203 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002204 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002205 this->onDrawTextBlob(blob, x, y, paint);
2206 }
2207}
reed@google.come0d9ce82014-04-23 04:00:17 +00002208
reed41af9662015-01-05 07:49:08 -08002209void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2210 const SkPoint verts[], const SkPoint texs[],
2211 const SkColor colors[], SkXfermode* xmode,
2212 const uint16_t indices[], int indexCount,
2213 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002214 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002215 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002216
reed@android.com8a1c16f2008-12-17 15:59:43 +00002217 while (iter.next()) {
2218 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002219 colors, xmode, indices, indexCount,
2220 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002221 }
reed@google.com4b226022011-01-11 18:32:13 +00002222
reed@google.com4e2b3d32011-04-07 14:18:59 +00002223 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002224}
2225
dandovb3c9d1c2014-08-12 08:34:29 -07002226void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2227 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002228 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002229 if (NULL == cubics) {
2230 return;
2231 }
mtklein6cfa73a2014-08-13 13:33:49 -07002232
dandovecfff212014-08-04 10:02:00 -07002233 // Since a patch is always within the convex hull of the control points, we discard it when its
2234 // bounding rectangle is completely outside the current clip.
2235 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002236 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002237 if (this->quickReject(bounds)) {
2238 return;
2239 }
mtklein6cfa73a2014-08-13 13:33:49 -07002240
dandovb3c9d1c2014-08-12 08:34:29 -07002241 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2242}
2243
2244void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2245 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2246
dandovecfff212014-08-04 10:02:00 -07002247 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002248
dandovecfff212014-08-04 10:02:00 -07002249 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002250 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002251 }
mtklein6cfa73a2014-08-13 13:33:49 -07002252
dandovecfff212014-08-04 10:02:00 -07002253 LOOPER_END
2254}
2255
reed3cb38402015-02-06 08:36:15 -08002256void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002257 if (dr && !this->quickReject(dr->getBounds())) {
2258 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002259 }
2260}
2261
reed3cb38402015-02-06 08:36:15 -08002262void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002263 dr->draw(this);
2264}
2265
reed@android.com8a1c16f2008-12-17 15:59:43 +00002266//////////////////////////////////////////////////////////////////////////////
2267// These methods are NOT virtual, and therefore must call back into virtual
2268// methods, rather than actually drawing themselves.
2269//////////////////////////////////////////////////////////////////////////////
2270
2271void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002272 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002273 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002274 SkPaint paint;
2275
2276 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002277 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002278 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002279 }
2280 this->drawPaint(paint);
2281}
2282
reed@android.com845fdac2009-06-23 03:01:32 +00002283void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002284 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002285 SkPaint paint;
2286
2287 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002288 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002289 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290 }
2291 this->drawPaint(paint);
2292}
2293
2294void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002295 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002296 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002297
reed@android.com8a1c16f2008-12-17 15:59:43 +00002298 pt.set(x, y);
2299 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2300}
2301
2302void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002303 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002304 SkPoint pt;
2305 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002306
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307 pt.set(x, y);
2308 paint.setColor(color);
2309 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2310}
2311
2312void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2313 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002314 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002315 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002316
reed@android.com8a1c16f2008-12-17 15:59:43 +00002317 pts[0].set(x0, y0);
2318 pts[1].set(x1, y1);
2319 this->drawPoints(kLines_PointMode, 2, pts, paint);
2320}
2321
2322void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2323 SkScalar right, SkScalar bottom,
2324 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002325 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002326 SkRect r;
2327
2328 r.set(left, top, right, bottom);
2329 this->drawRect(r, paint);
2330}
2331
2332void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2333 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002334 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002335 if (radius < 0) {
2336 radius = 0;
2337 }
2338
2339 SkRect r;
2340 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002341 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002342}
2343
2344void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2345 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002346 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002347 if (rx > 0 && ry > 0) {
2348 if (paint.canComputeFastBounds()) {
2349 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002350 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002351 return;
2352 }
2353 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002354 SkRRect rrect;
2355 rrect.setRectXY(r, rx, ry);
2356 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002357 } else {
2358 this->drawRect(r, paint);
2359 }
2360}
2361
reed@android.com8a1c16f2008-12-17 15:59:43 +00002362void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2363 SkScalar sweepAngle, bool useCenter,
2364 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002365 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002366 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2367 this->drawOval(oval, paint);
2368 } else {
2369 SkPath path;
2370 if (useCenter) {
2371 path.moveTo(oval.centerX(), oval.centerY());
2372 }
2373 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2374 if (useCenter) {
2375 path.close();
2376 }
2377 this->drawPath(path, paint);
2378 }
2379}
2380
2381void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2382 const SkPath& path, SkScalar hOffset,
2383 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002384 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002385 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002386
reed@android.com8a1c16f2008-12-17 15:59:43 +00002387 matrix.setTranslate(hOffset, vOffset);
2388 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2389}
2390
reed@android.comf76bacf2009-05-13 14:00:33 +00002391///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002392void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002393 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002394 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002395 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002396 }
2397}
2398
reedd5fa1a42014-08-09 11:08:05 -07002399void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002400 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002401 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002402 if (matrix && matrix->isIdentity()) {
2403 matrix = NULL;
2404 }
2405 this->onDrawPicture(picture, matrix, paint);
2406 }
2407}
robertphillips9b14f262014-06-04 05:40:44 -07002408
reedd5fa1a42014-08-09 11:08:05 -07002409void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2410 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002411 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002412 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002413 // Canvas has to first give the device the opportunity to render
2414 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002415 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002416 return; // the device has rendered the entire picture
2417 }
2418 }
2419
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002420 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002421
robertphillipsc5ba71d2014-09-04 08:42:50 -07002422 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002423}
2424
reed@android.com8a1c16f2008-12-17 15:59:43 +00002425///////////////////////////////////////////////////////////////////////////////
2426///////////////////////////////////////////////////////////////////////////////
2427
2428SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002429 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002430
2431 SkASSERT(canvas);
2432
2433 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2434 fDone = !fImpl->next();
2435}
2436
2437SkCanvas::LayerIter::~LayerIter() {
2438 fImpl->~SkDrawIter();
2439}
2440
2441void SkCanvas::LayerIter::next() {
2442 fDone = !fImpl->next();
2443}
2444
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002445SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002446 return fImpl->getDevice();
2447}
2448
2449const SkMatrix& SkCanvas::LayerIter::matrix() const {
2450 return fImpl->getMatrix();
2451}
2452
2453const SkPaint& SkCanvas::LayerIter::paint() const {
2454 const SkPaint* paint = fImpl->getPaint();
2455 if (NULL == paint) {
2456 paint = &fDefaultPaint;
2457 }
2458 return *paint;
2459}
2460
2461const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2462int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2463int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002464
2465///////////////////////////////////////////////////////////////////////////////
2466
fmalitac3b589a2014-06-05 12:40:07 -07002467SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002468
2469///////////////////////////////////////////////////////////////////////////////
2470
2471static bool supported_for_raster_canvas(const SkImageInfo& info) {
2472 switch (info.alphaType()) {
2473 case kPremul_SkAlphaType:
2474 case kOpaque_SkAlphaType:
2475 break;
2476 default:
2477 return false;
2478 }
2479
2480 switch (info.colorType()) {
2481 case kAlpha_8_SkColorType:
2482 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002483 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002484 break;
2485 default:
2486 return false;
2487 }
2488
2489 return true;
2490}
2491
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002492SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2493 if (!supported_for_raster_canvas(info)) {
2494 return NULL;
2495 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002496
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002497 SkBitmap bitmap;
2498 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2499 return NULL;
2500 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002501 return SkNEW_ARGS(SkCanvas, (bitmap));
2502}
reedd5fa1a42014-08-09 11:08:05 -07002503
2504///////////////////////////////////////////////////////////////////////////////
2505
2506SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002507 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002508 : fCanvas(canvas)
2509 , fSaveCount(canvas->getSaveCount())
2510{
bsalomon49f085d2014-09-05 13:34:00 -07002511 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002512 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002513 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002514 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002515 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002516 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002517 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002518 canvas->save();
2519 }
mtklein6cfa73a2014-08-13 13:33:49 -07002520
bsalomon49f085d2014-09-05 13:34:00 -07002521 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002522 canvas->concat(*matrix);
2523 }
2524}
2525
2526SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2527 fCanvas->restoreToCount(fSaveCount);
2528}