blob: 63a9241f60ec950f3d8bbed87e9aaa3b045b31de [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
mtkleinfeaadee2015-04-08 11:25:48 -0700138 void reset(const SkIRect& bounds) {
139 SkASSERT(!fPaint);
140 SkASSERT(!fNext);
141 SkASSERT(fDevice);
142 fClip.setRect(bounds);
143 }
144
reed@google.com045e62d2011-10-24 12:19:46 +0000145 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
146 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000147 int x = fDevice->getOrigin().x();
148 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 int width = fDevice->width();
150 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000151
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 if ((x | y) == 0) {
153 fMatrix = &totalMatrix;
154 fClip = totalClip;
155 } else {
156 fMatrixStorage = totalMatrix;
157 fMatrixStorage.postTranslate(SkIntToScalar(-x),
158 SkIntToScalar(-y));
159 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000160
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 totalClip.translate(-x, -y, &fClip);
162 }
163
reed@google.com045e62d2011-10-24 12:19:46 +0000164 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165
166 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000167
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000169 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170 SkRegion::kDifference_Op);
171 }
reed@google.com4b226022011-01-11 18:32:13 +0000172
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000173 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
174
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175#ifdef SK_DEBUG
176 if (!fClip.isEmpty()) {
177 SkIRect deviceR;
178 deviceR.set(0, 0, width, height);
179 SkASSERT(deviceR.contains(fClip.getBounds()));
180 }
181#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000182 }
183
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184private:
bsalomon@google.com0e354aa2012-10-08 20:44:25 +0000185 SkMatrix fMatrixStorage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186};
187
188/* This is the record we keep for each save/restore level in the stack.
189 Since a level optionally copies the matrix and/or stack, we have pointers
190 for these fields. If the value is copied for this level, the copy is
191 stored in the ...Storage field, and the pointer points to that. If the
192 value is not copied for this level, we ignore ...Storage, and just point
193 at the corresponding value in the previous level in the stack.
194*/
195class SkCanvas::MCRec {
196public:
reed1f836ee2014-07-07 07:49:34 -0700197 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700198 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 /* If there are any layers in the stack, this points to the top-most
200 one that is at or below this level in the stack (so we know what
201 bitmap/device to draw into from this level. This value is NOT
202 reference counted, since the real owner is either our fLayer field,
203 or a previous one in a lower level.)
204 */
reed2ff1fce2014-12-11 07:07:37 -0800205 DeviceCM* fTopLayer;
206 SkRasterClip fRasterClip;
207 SkMatrix fMatrix;
208 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209
reedd9544982014-09-09 18:46:22 -0700210 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
reedd9544982014-09-09 18:46:22 -0700211 fFilter = NULL;
212 fLayer = NULL;
213 fTopLayer = NULL;
reed2ff1fce2014-12-11 07:07:37 -0800214 fMatrix.reset();
215 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700216
reedd9544982014-09-09 18:46:22 -0700217 // don't bother initializing fNext
218 inc_rec();
219 }
reed2ff1fce2014-12-11 07:07:37 -0800220 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700221 fFilter = SkSafeRef(prev.fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 fLayer = NULL;
reedd9544982014-09-09 18:46:22 -0700223 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800224 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700225
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 // don't bother initializing fNext
227 inc_rec();
228 }
229 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000230 SkSafeUnref(fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231 SkDELETE(fLayer);
232 dec_rec();
233 }
mtkleinfeaadee2015-04-08 11:25:48 -0700234
235 void reset(const SkIRect& bounds) {
236 SkASSERT(fLayer);
237 SkASSERT(fDeferredSaveCount == 0);
238
239 fMatrix.reset();
240 fRasterClip.setRect(bounds);
241 fLayer->reset(bounds);
242 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243};
244
245class SkDrawIter : public SkDraw {
246public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000247 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000248 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000249 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250 canvas->updateDeviceCMCache();
251
reed687fa1c2015-04-07 08:00:56 -0700252 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000254 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 }
reed@google.com4b226022011-01-11 18:32:13 +0000256
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 bool next() {
258 // skip over recs with empty clips
259 if (fSkipEmptyClips) {
260 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
261 fCurrLayer = fCurrLayer->fNext;
262 }
263 }
264
reed@google.comf68c5e22012-02-24 16:38:58 +0000265 const DeviceCM* rec = fCurrLayer;
266 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267
268 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000269 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
270 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 fDevice = rec->fDevice;
272 fBitmap = &fDevice->accessBitmap(true);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000274 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275
276 fCurrLayer = rec->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 // fCurrLayer may be NULL now
reed@android.com199f1082009-06-10 02:12:47 +0000278
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 return true;
280 }
281 return false;
282 }
reed@google.com4b226022011-01-11 18:32:13 +0000283
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000284 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000285 int getX() const { return fDevice->getOrigin().x(); }
286 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287 const SkMatrix& getMatrix() const { return *fMatrix; }
288 const SkRegion& getClip() const { return *fClip; }
289 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000290
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291private:
292 SkCanvas* fCanvas;
293 const DeviceCM* fCurrLayer;
294 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295 SkBool8 fSkipEmptyClips;
296
297 typedef SkDraw INHERITED;
298};
299
300/////////////////////////////////////////////////////////////////////////////
301
302class AutoDrawLooper {
303public:
reed4a8126e2014-09-22 07:29:03 -0700304 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000305 bool skipLayerForImageFilter = false,
306 const SkRect* bounds = NULL) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000307 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000308 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700309 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000310 fSaveCount = canvas->getSaveCount();
reed@google.com8926b162012-03-23 15:36:36 +0000311 fDoClearImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000312 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313
reed1b110d62015-03-08 18:47:13 -0700314 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) {
reed@google.com8926b162012-03-23 15:36:36 +0000315 SkPaint tmp;
reed1b110d62015-03-08 18:47:13 -0700316 tmp.setImageFilter(fOrigPaint.getImageFilter());
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000317 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
reed76033be2015-03-14 10:54:31 -0700318 SkCanvas::kFullLayer_SaveLayerStrategy);
reed@google.com8926b162012-03-23 15:36:36 +0000319 // we'll clear the imageFilter for the actual draws in next(), so
320 // it will only be applied during the restore().
321 fDoClearImageFilter = true;
322 }
323
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000324 if (SkDrawLooper* looper = paint.getLooper()) {
325 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
326 looper->contextSize());
327 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000328 fIsSimple = false;
329 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000330 fLooperContext = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000331 // can we be marked as simple?
332 fIsSimple = !fFilter && !fDoClearImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000333 }
piotaixrb5fae932014-09-24 13:03:30 -0700334
reed4a8126e2014-09-22 07:29:03 -0700335 uint32_t oldFlags = paint.getFlags();
336 fNewPaintFlags = filter_paint_flags(props, oldFlags);
337 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reed1b110d62015-03-08 18:47:13 -0700338 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700339 paint->setFlags(fNewPaintFlags);
340 fPaint = paint;
341 // if we're not simple, doNext() will take care of calling setFlags()
342 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000343 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000344
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 ~AutoDrawLooper() {
reed@google.com8926b162012-03-23 15:36:36 +0000346 if (fDoClearImageFilter) {
347 fCanvas->internalRestore();
348 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000349 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000351
reed@google.com4e2b3d32011-04-07 14:18:59 +0000352 const SkPaint& paint() const {
353 SkASSERT(fPaint);
354 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000356
reed@google.com129ec222012-05-15 13:24:09 +0000357 bool next(SkDrawFilter::Type drawType) {
358 if (fDone) {
359 return false;
360 } else if (fIsSimple) {
361 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000362 return !fPaint->nothingToDraw();
363 } else {
364 return this->doNext(drawType);
365 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000366 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000367
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368private:
reed1b110d62015-03-08 18:47:13 -0700369 SkLazyPaint fLazyPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000370 SkCanvas* fCanvas;
371 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000372 SkDrawFilter* fFilter;
373 const SkPaint* fPaint;
374 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700375 uint32_t fNewPaintFlags;
reed@google.com8926b162012-03-23 15:36:36 +0000376 bool fDoClearImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000377 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000378 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000379 SkDrawLooper::Context* fLooperContext;
380 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000381
382 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383};
384
reed@google.com129ec222012-05-15 13:24:09 +0000385bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
reed@google.com632e1a22011-10-06 12:37:00 +0000386 fPaint = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000387 SkASSERT(!fIsSimple);
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000388 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000389
reed1b110d62015-03-08 18:47:13 -0700390 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700391 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000392
393 if (fDoClearImageFilter) {
394 paint->setImageFilter(NULL);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000395 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000396
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000397 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000398 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000399 return false;
400 }
401 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000402 if (!fFilter->filter(paint, drawType)) {
403 fDone = true;
404 return false;
405 }
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000406 if (NULL == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000407 // no looper means we only draw once
408 fDone = true;
409 }
410 }
411 fPaint = paint;
412
413 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000414 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000415 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000416 }
417
418 // call this after any possible paint modifiers
419 if (fPaint->nothingToDraw()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000420 fPaint = NULL;
421 return false;
422 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000423 return true;
424}
425
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426////////// macros to place around the internal draw calls //////////////////
427
reed@google.com8926b162012-03-23 15:36:36 +0000428#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000429 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700430 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000431 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000432 SkDrawIter iter(this);
433
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000434#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000435 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700436 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000437 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000439
reed@google.com4e2b3d32011-04-07 14:18:59 +0000440#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441
442////////////////////////////////////////////////////////////////////////////
443
mtkleinfeaadee2015-04-08 11:25:48 -0700444void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
445 this->restoreToCount(1);
446 fCachedLocalClipBounds.setEmpty();
447 fCachedLocalClipBoundsDirty = true;
448 fClipStack->reset();
449 fMCRec->reset(bounds);
450
451 // We're peering through a lot of structs here. Only at this scope do we
452 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
453 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
454}
455
reedd9544982014-09-09 18:46:22 -0700456SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
457 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
reed@google.comc0784db2013-12-13 21:16:12 +0000458 fCachedLocalClipBounds.setEmpty();
459 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000460 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000461 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700462 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800463 fSaveCount = 1;
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000464 fMetaData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000465
reed687fa1c2015-04-07 08:00:56 -0700466 fClipStack.reset(SkNEW(SkClipStack));
467
reed@android.com8a1c16f2008-12-17 15:59:43 +0000468 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700469 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000470
reedb679ca82015-04-07 04:40:48 -0700471 SkASSERT(sizeof(DeviceCM) <= sizeof(fBaseLayerStorage));
472 fMCRec->fLayer = (DeviceCM*)fBaseLayerStorage;
473 new (fBaseLayerStorage) DeviceCM(NULL, NULL, NULL, fConservativeRasterClip);
474
reed@android.com8a1c16f2008-12-17 15:59:43 +0000475 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000476
reed@google.com97af1a62012-08-28 12:19:02 +0000477 fSurfaceBase = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000478
reedf92c8662014-08-18 08:02:43 -0700479 if (device) {
reedb2db8982014-11-13 12:41:02 -0800480 device->initForRootLayer(fProps.pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700481 if (device->forceConservativeRasterClip()) {
482 fConservativeRasterClip = true;
483 }
reedf92c8662014-08-18 08:02:43 -0700484 device->onAttachToCanvas(this);
485 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800486 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700487 }
488 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000489}
490
reed@google.comcde92112011-07-06 20:00:52 +0000491SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000492 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700493 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000494{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000495 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000496
reedd9544982014-09-09 18:46:22 -0700497 this->init(NULL, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000498}
499
reedd9544982014-09-09 18:46:22 -0700500static SkBitmap make_nopixels(int width, int height) {
501 SkBitmap bitmap;
502 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
503 return bitmap;
504}
505
506class SkNoPixelsBitmapDevice : public SkBitmapDevice {
507public:
reed78e27682014-11-19 08:04:34 -0800508 SkNoPixelsBitmapDevice(const SkIRect& bounds)
509 : INHERITED(make_nopixels(bounds.width(), bounds.height()))
510 {
511 this->setOrigin(bounds.x(), bounds.y());
512 }
reedd9544982014-09-09 18:46:22 -0700513
514private:
piotaixrb5fae932014-09-24 13:03:30 -0700515
reedd9544982014-09-09 18:46:22 -0700516 typedef SkBitmapDevice INHERITED;
517};
518
reed96a857e2015-01-25 10:33:58 -0800519SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000520 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800521 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000522{
523 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700524
reed78e27682014-11-19 08:04:34 -0800525 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
526 (SkIRect::MakeWH(width, height))), kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700527}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000528
reed78e27682014-11-19 08:04:34 -0800529SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700530 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700531 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700532{
533 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700534
reed78e27682014-11-19 08:04:34 -0800535 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds)), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700536}
537
reed4a8126e2014-09-22 07:29:03 -0700538SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700539 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700540 , fProps(SkSurfacePropsCopyOrDefault(props))
reedd9544982014-09-09 18:46:22 -0700541{
542 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700543
reedd9544982014-09-09 18:46:22 -0700544 this->init(device, flags);
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000545}
546
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000547SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000548 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700549 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000550{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000551 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700552
reedd9544982014-09-09 18:46:22 -0700553 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000554}
555
reed4a8126e2014-09-22 07:29:03 -0700556SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700557 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700558 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700559{
560 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700561
reed4a8126e2014-09-22 07:29:03 -0700562 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
563 this->init(device, kDefault_InitFlags);
564}
reed29c857d2014-09-21 10:25:07 -0700565
reed4a8126e2014-09-22 07:29:03 -0700566SkCanvas::SkCanvas(const SkBitmap& bitmap)
567 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
568 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
569{
570 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700571
reed4a8126e2014-09-22 07:29:03 -0700572 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
573 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574}
575
576SkCanvas::~SkCanvas() {
577 // free up the contents of our deque
578 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000579
reed@android.com8a1c16f2008-12-17 15:59:43 +0000580 this->internalRestore(); // restore the last, since we're going away
581
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000582 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000583
reed@android.com8a1c16f2008-12-17 15:59:43 +0000584 dec_canvas();
585}
586
reed@android.com8a1c16f2008-12-17 15:59:43 +0000587SkDrawFilter* SkCanvas::getDrawFilter() const {
588 return fMCRec->fFilter;
589}
590
591SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
592 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
593 return filter;
594}
595
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000596SkMetaData& SkCanvas::getMetaData() {
597 // metadata users are rare, so we lazily allocate it. If that changes we
598 // can decide to just make it a field in the device (rather than a ptr)
599 if (NULL == fMetaData) {
600 fMetaData = new SkMetaData;
601 }
602 return *fMetaData;
603}
604
reed@android.com8a1c16f2008-12-17 15:59:43 +0000605///////////////////////////////////////////////////////////////////////////////
606
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000607void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000608 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000609 if (device) {
610 device->flush();
611 }
612}
613
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000614SkISize SkCanvas::getTopLayerSize() const {
615 SkBaseDevice* d = this->getTopDevice();
616 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
617}
618
619SkIPoint SkCanvas::getTopLayerOrigin() const {
620 SkBaseDevice* d = this->getTopDevice();
621 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
622}
623
624SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000625 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000626 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
627}
628
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000629SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000630 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000631 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000632 SkASSERT(rec && rec->fLayer);
633 return rec->fLayer->fDevice;
634}
635
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000636SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000637 if (updateMatrixClip) {
638 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
639 }
reed@google.com9266fed2011-03-30 00:18:03 +0000640 return fMCRec->fTopLayer->fDevice;
641}
642
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000643bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
644 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
645 return false;
646 }
647
648 bool weAllocated = false;
649 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700650 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000651 return false;
652 }
653 weAllocated = true;
654 }
655
656 SkBitmap bm(*bitmap);
657 bm.lockPixels();
658 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
659 return true;
660 }
661
662 if (weAllocated) {
663 bitmap->setPixelRef(NULL);
664 }
665 return false;
666}
reed@google.com51df9e32010-12-23 19:29:18 +0000667
bsalomon@google.comc6980972011-11-02 19:57:21 +0000668bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000669 SkIRect r = srcRect;
670 const SkISize size = this->getBaseLayerSize();
671 if (!r.intersect(0, 0, size.width(), size.height())) {
672 bitmap->reset();
673 return false;
674 }
675
reed84825042014-09-02 12:50:45 -0700676 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000677 // bitmap will already be reset.
678 return false;
679 }
680 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
681 bitmap->reset();
682 return false;
683 }
684 return true;
685}
686
reed96472de2014-12-10 09:53:42 -0800687bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000688 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000689 if (!device) {
690 return false;
691 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000692 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800693
reed96472de2014-12-10 09:53:42 -0800694 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
695 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000696 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000697 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000698
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000699 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800700 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000701}
702
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000703bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
704 if (bitmap.getTexture()) {
705 return false;
706 }
707 SkBitmap bm(bitmap);
708 bm.lockPixels();
709 if (bm.getPixels()) {
710 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
711 }
712 return false;
713}
714
715bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
716 int x, int y) {
717 switch (origInfo.colorType()) {
718 case kUnknown_SkColorType:
719 case kIndex_8_SkColorType:
720 return false;
721 default:
722 break;
723 }
724 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
725 return false;
726 }
727
728 const SkISize size = this->getBaseLayerSize();
729 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
730 if (!target.intersect(0, 0, size.width(), size.height())) {
731 return false;
732 }
733
734 SkBaseDevice* device = this->getDevice();
735 if (!device) {
736 return false;
737 }
738
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000739 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700740 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000741
742 // if x or y are negative, then we have to adjust pixels
743 if (x > 0) {
744 x = 0;
745 }
746 if (y > 0) {
747 y = 0;
748 }
749 // here x,y are either 0 or negative
750 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
751
reed4af35f32014-06-27 17:47:49 -0700752 // Tell our owning surface to bump its generation ID
753 this->predrawNotify();
754
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000755 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000756 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000757}
reed@google.com51df9e32010-12-23 19:29:18 +0000758
junov@google.com4370aed2012-01-18 16:21:08 +0000759SkCanvas* SkCanvas::canvasForDrawIter() {
760 return this;
761}
762
reed@android.com8a1c16f2008-12-17 15:59:43 +0000763//////////////////////////////////////////////////////////////////////////////
764
reed@android.com8a1c16f2008-12-17 15:59:43 +0000765void SkCanvas::updateDeviceCMCache() {
766 if (fDeviceCMDirty) {
767 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700768 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000770
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771 if (NULL == layer->fNext) { // only one layer
reed687fa1c2015-04-07 08:00:56 -0700772 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000774 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000775 do {
reed687fa1c2015-04-07 08:00:56 -0700776 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000777 } while ((layer = layer->fNext) != NULL);
778 }
779 fDeviceCMDirty = false;
780 }
781}
782
reed@android.com8a1c16f2008-12-17 15:59:43 +0000783///////////////////////////////////////////////////////////////////////////////
784
reed2ff1fce2014-12-11 07:07:37 -0800785void SkCanvas::checkForDeferredSave() {
786 if (fMCRec->fDeferredSaveCount > 0) {
787 fMCRec->fDeferredSaveCount -= 1;
788 this->doSave();
789 }
790}
791
reedf0090cb2014-11-26 08:55:51 -0800792int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800793#ifdef SK_DEBUG
794 int count = 0;
795 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
796 for (;;) {
797 const MCRec* rec = (const MCRec*)iter.next();
798 if (!rec) {
799 break;
800 }
801 count += 1 + rec->fDeferredSaveCount;
802 }
803 SkASSERT(count == fSaveCount);
804#endif
805 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800806}
807
808int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800809 fSaveCount += 1;
810 fMCRec->fDeferredSaveCount += 1;
811 return this->getSaveCount() - 1; // return our prev value
812}
813
814void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800815 this->willSave();
reed2ff1fce2014-12-11 07:07:37 -0800816 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800817}
818
819void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800820 if (fMCRec->fDeferredSaveCount > 0) {
821 SkASSERT(fSaveCount > 1);
822 fSaveCount -= 1;
823 fMCRec->fDeferredSaveCount -= 1;
824 } else {
825 // check for underflow
826 if (fMCStack.count() > 1) {
827 this->willRestore();
828 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700829 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800830 this->internalRestore();
831 this->didRestore();
832 }
reedf0090cb2014-11-26 08:55:51 -0800833 }
834}
835
836void SkCanvas::restoreToCount(int count) {
837 // sanity check
838 if (count < 1) {
839 count = 1;
840 }
mtkleinf0f14112014-12-12 08:46:25 -0800841
reedf0090cb2014-11-26 08:55:51 -0800842 int n = this->getSaveCount() - count;
843 for (int i = 0; i < n; ++i) {
844 this->restore();
845 }
846}
847
reed2ff1fce2014-12-11 07:07:37 -0800848void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000849 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700850 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000852
reed687fa1c2015-04-07 08:00:56 -0700853 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000854}
855
reed@android.com8a1c16f2008-12-17 15:59:43 +0000856static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000857#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000858 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000859#else
860 return true;
861#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000862}
863
junov@chromium.orga907ac32012-02-24 21:54:07 +0000864bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700865 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000866 SkIRect clipBounds;
867 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000868 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000869 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000870
reed96e657d2015-03-10 17:30:07 -0700871 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
872
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000873 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700874 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000875 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000876 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700877 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000878 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000879
reed96e657d2015-03-10 17:30:07 -0700880 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000881 r.roundOut(&ir);
882 // early exit if the layer's bounds are clipped out
883 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000884 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700885 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700886 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000887 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000888 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000889 }
890 } else { // no user bounds, so just use the clip
891 ir = clipBounds;
892 }
reed180aec42015-03-11 10:39:04 -0700893 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000894
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000895 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -0700896 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -0700897 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -0700898 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -0700899 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000900 }
901
902 if (intersection) {
903 *intersection = ir;
904 }
905 return true;
906}
907
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000908int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800909 if (gIgnoreSaveLayerBounds) {
910 bounds = NULL;
911 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000912 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -0700913 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700914 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800915 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000916}
917
reed2ff1fce2014-12-11 07:07:37 -0800918int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800919 if (gIgnoreSaveLayerBounds) {
920 bounds = NULL;
921 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000922 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -0700923 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700924 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800925 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000926}
927
reed2ff1fce2014-12-11 07:07:37 -0800928void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -0700929 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000930#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000931 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000932#endif
933
junov@chromium.orga907ac32012-02-24 21:54:07 +0000934 // do this before we create the layer. We don't call the public save() since
935 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -0800936 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000937
938 fDeviceCMDirty = true;
939
940 SkIRect ir;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000941 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -0800942 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000943 }
944
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000945 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
946 // the clipRectBounds() call above?
947 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -0800948 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000949 }
950
reed76033be2015-03-14 10:54:31 -0700951 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -0700952 SkPixelGeometry geo = fProps.pixelGeometry();
953 if (paint) {
reed76033be2015-03-14 10:54:31 -0700954 // TODO: perhaps add a query to filters so we might preserve opaqueness...
955 if (paint->getImageFilter() || paint->getColorFilter()) {
956 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -0700957 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +0000958 }
959 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000960 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
961 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962
reedb2db8982014-11-13 12:41:02 -0800963 SkBaseDevice* device = this->getTopDevice();
964 if (NULL == device) {
965 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800966 return;
reed@google.com76dd2772012-01-05 21:15:07 +0000967 }
reedb2db8982014-11-13 12:41:02 -0800968
reed76033be2015-03-14 10:54:31 -0700969 SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed8dc0ccb2015-03-20 06:32:52 -0700970 device = device->onCreateDevice(SkBaseDevice::CreateInfo(info, usage, geo), paint);
bungeman@google.come25c6842011-08-17 14:53:54 +0000971 if (NULL == device) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800972 SkErrorInternals::SetError( kInternalError_SkError,
973 "Unable to create device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800974 return;
bungeman@google.come25c6842011-08-17 14:53:54 +0000975 }
bsalomon@google.come97f0852011-06-17 13:10:25 +0000976
reed@google.com6f8f2922011-03-04 22:27:10 +0000977 device->setOrigin(ir.fLeft, ir.fTop);
reed96e657d2015-03-10 17:30:07 -0700978 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979 device->unref();
980
981 layer->fNext = fMCRec->fTopLayer;
982 fMCRec->fLayer = layer;
983 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +0000984}
985
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000986int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
987 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
988}
989
reed@android.com8a1c16f2008-12-17 15:59:43 +0000990int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
991 SaveFlags flags) {
992 if (0xFF == alpha) {
993 return this->saveLayer(bounds, NULL, flags);
994 } else {
995 SkPaint tmpPaint;
996 tmpPaint.setAlpha(alpha);
997 return this->saveLayer(bounds, &tmpPaint, flags);
998 }
999}
1000
reed@android.com8a1c16f2008-12-17 15:59:43 +00001001void SkCanvas::internalRestore() {
1002 SkASSERT(fMCStack.count() != 0);
1003
1004 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001005 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001006
reed687fa1c2015-04-07 08:00:56 -07001007 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001008
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001009 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001010 DeviceCM* layer = fMCRec->fLayer; // may be null
1011 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1012 fMCRec->fLayer = NULL;
1013
1014 // now do the normal restore()
1015 fMCRec->~MCRec(); // balanced in save()
1016 fMCStack.pop_back();
1017 fMCRec = (MCRec*)fMCStack.back();
1018
1019 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1020 since if we're being recorded, we don't want to record this (the
1021 recorder will have already recorded the restore).
1022 */
bsalomon49f085d2014-09-05 13:34:00 -07001023 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001024 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001025 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001026 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1027 layer->fPaint);
1028 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029 fDeviceCMDirty = true;
reedb679ca82015-04-07 04:40:48 -07001030 SkDELETE(layer);
1031 } else {
1032 // we're at the root
1033 SkASSERT(layer == (void*)fBaseLayerStorage);
1034 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001035 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001036 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037}
1038
reed4a8126e2014-09-22 07:29:03 -07001039SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1040 if (NULL == props) {
1041 props = &fProps;
1042 }
1043 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001044}
1045
reed4a8126e2014-09-22 07:29:03 -07001046SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001047 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001048 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001049}
1050
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001051SkImageInfo SkCanvas::imageInfo() const {
1052 SkBaseDevice* dev = this->getDevice();
1053 if (dev) {
1054 return dev->imageInfo();
1055 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001056 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001057 }
1058}
1059
1060const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1061 return this->onPeekPixels(info, rowBytes);
1062}
1063
1064const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1065 SkBaseDevice* dev = this->getDevice();
1066 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1067}
1068
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001069void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1070 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1071 if (pixels && origin) {
1072 *origin = this->getTopDevice(false)->getOrigin();
1073 }
1074 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001075}
1076
1077void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1078 SkBaseDevice* dev = this->getTopDevice();
1079 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1080}
1081
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001082SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1083 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1084 if (NULL == fAddr) {
1085 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001086 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001087 return; // failure, fAddr is NULL
1088 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001089 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1090 return; // failure, fAddr is NULL
1091 }
1092 fAddr = fBitmap.getPixels();
1093 fRowBytes = fBitmap.rowBytes();
1094 }
1095 SkASSERT(fAddr); // success
1096}
1097
1098bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1099 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001100 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001101 } else {
1102 bitmap->reset();
1103 return false;
1104 }
1105}
1106
reed@android.com8a1c16f2008-12-17 15:59:43 +00001107/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001108void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001109 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001110 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001111 return;
1112 }
1113
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001114 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001115 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001116 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001117 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001118
1119 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001120
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001121 SkRect storage;
1122 const SkRect* bounds = NULL;
1123 if (paint && paint->canComputeFastBounds()) {
1124 bitmap.getBounds(&storage);
1125 matrix.mapRect(&storage);
1126 bounds = &paint->computeFastBounds(storage, &storage);
1127 }
1128
1129 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001130
1131 while (iter.next()) {
1132 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1133 }
1134
1135 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001136}
1137
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001138void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed@google.com8926b162012-03-23 15:36:36 +00001139 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001140 SkPaint tmp;
1141 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001142 paint = &tmp;
1143 }
reed@google.com4b226022011-01-11 18:32:13 +00001144
reed@google.com8926b162012-03-23 15:36:36 +00001145 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001146 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001147 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001148 paint = &looper.paint();
1149 SkImageFilter* filter = paint->getImageFilter();
1150 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001151 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001152 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001153 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001154 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001155 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001156 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001157 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001158 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001159 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001160 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001161 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001162 SkPaint tmpUnfiltered(*paint);
1163 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001164 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1165 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001166 }
1167 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001168 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001169 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001170 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001171 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001172}
1173
reed41af9662015-01-05 07:49:08 -08001174void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001175 if (gTreatSpriteAsBitmap) {
1176 this->save();
1177 this->resetMatrix();
1178 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1179 this->restore();
1180 return;
1181 }
1182
danakj9881d632014-11-26 12:41:06 -08001183 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001184 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001185 return;
1186 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001187 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001188
reed@google.com8926b162012-03-23 15:36:36 +00001189 SkPaint tmp;
1190 if (NULL == paint) {
1191 paint = &tmp;
1192 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001193
reed@google.com8926b162012-03-23 15:36:36 +00001194 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001195
reed@google.com8926b162012-03-23 15:36:36 +00001196 while (iter.next()) {
1197 paint = &looper.paint();
1198 SkImageFilter* filter = paint->getImageFilter();
1199 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1200 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001201 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001202 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001203 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001204 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001205 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001206 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001207 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001208 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001209 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001210 SkPaint tmpUnfiltered(*paint);
1211 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001212 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001213 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001214 }
1215 } else {
1216 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1217 }
1218 }
1219 LOOPER_END
1220}
1221
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001223void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001224 SkMatrix m;
1225 m.setTranslate(dx, dy);
1226 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001227}
1228
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001229void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001230 SkMatrix m;
1231 m.setScale(sx, sy);
1232 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001233}
1234
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001235void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001236 SkMatrix m;
1237 m.setRotate(degrees);
1238 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239}
1240
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001241void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001242 SkMatrix m;
1243 m.setSkew(sx, sy);
1244 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001245}
1246
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001247void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001248 if (matrix.isIdentity()) {
1249 return;
1250 }
1251
reed2ff1fce2014-12-11 07:07:37 -08001252 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001253 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001254 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001255 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001256
1257 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001258}
1259
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001261 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001262 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001263 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001264 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001265 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266}
1267
reed@android.com8a1c16f2008-12-17 15:59:43 +00001268void SkCanvas::resetMatrix() {
1269 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001270
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271 matrix.reset();
1272 this->setMatrix(matrix);
1273}
1274
1275//////////////////////////////////////////////////////////////////////////////
1276
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001277void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001278 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001279 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1280 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001281}
1282
1283void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001284#ifdef SK_ENABLE_CLIP_QUICKREJECT
1285 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001286 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001287 return false;
1288 }
1289
reed@google.com3b3e8952012-08-16 20:53:31 +00001290 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001291 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001292 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001293
reed687fa1c2015-04-07 08:00:56 -07001294 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001295 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001296 }
1297 }
1298#endif
1299
reed@google.com5c3d1472011-02-22 19:12:23 +00001300 AutoValidateClip avc(this);
1301
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001303 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001304 if (!fAllowSoftClip) {
1305 edgeStyle = kHard_ClipEdgeStyle;
1306 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001307
reed1f836ee2014-07-07 07:49:34 -07001308 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001309 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001310 // the matrix. This means we don't have to a) make a path, and b) tell
1311 // the region code to scan-convert the path, only to discover that it
1312 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001313 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314
reed1f836ee2014-07-07 07:49:34 -07001315 fMCRec->fMatrix.mapRect(&r, rect);
reed687fa1c2015-04-07 08:00:56 -07001316 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001317 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001318 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001319 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001320 // and clip against that, since it can handle any matrix. However, to
1321 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1322 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323 SkPath path;
1324
1325 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001326 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001327 }
1328}
1329
reed73e714e2014-09-04 09:02:23 -07001330static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1331 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001332 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001333}
1334
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001335void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001336 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001337 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001338 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001339 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1340 } else {
1341 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001342 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001343}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001344
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001345void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001346 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001347 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001348 AutoValidateClip avc(this);
1349
1350 fDeviceCMDirty = true;
1351 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001352 if (!fAllowSoftClip) {
1353 edgeStyle = kHard_ClipEdgeStyle;
1354 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001355
reed687fa1c2015-04-07 08:00:56 -07001356 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001357
1358 SkPath devPath;
1359 devPath.addRRect(transformedRRect);
1360
reed73e714e2014-09-04 09:02:23 -07001361 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001362 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001363 }
1364
1365 SkPath path;
1366 path.addRRect(rrect);
1367 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001368 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001369}
1370
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001371void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001372 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001373 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1374 SkRect r;
1375 if (!path.isInverseFillType() && path.isRect(&r)) {
1376 this->onClipRect(r, op, edgeStyle);
1377 } else {
1378 this->onClipPath(path, op, edgeStyle);
1379 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001380}
1381
1382void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001383#ifdef SK_ENABLE_CLIP_QUICKREJECT
1384 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001385 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001386 return false;
1387 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001388
reed@google.com3b3e8952012-08-16 20:53:31 +00001389 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001390 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001391 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001392
reed687fa1c2015-04-07 08:00:56 -07001393 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001394 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001395 }
1396 }
1397#endif
1398
reed@google.com5c3d1472011-02-22 19:12:23 +00001399 AutoValidateClip avc(this);
1400
reed@android.com8a1c16f2008-12-17 15:59:43 +00001401 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001402 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001403 if (!fAllowSoftClip) {
1404 edgeStyle = kHard_ClipEdgeStyle;
1405 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001406
1407 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001408 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001409
reed@google.comfe701122011-11-08 19:41:23 +00001410 // Check if the transfomation, or the original path itself
1411 // made us empty. Note this can also happen if we contained NaN
1412 // values. computing the bounds detects this, and will set our
1413 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1414 if (devPath.getBounds().isEmpty()) {
1415 // resetting the path will remove any NaN or other wanky values
1416 // that might upset our scan converter.
1417 devPath.reset();
1418 }
1419
reed@google.com5c3d1472011-02-22 19:12:23 +00001420 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001421 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001422
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001423 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001424 bool clipIsAA = getClipStack()->asPath(&devPath);
1425 if (clipIsAA) {
1426 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001427 }
fmalita1a481fe2015-02-04 07:39:34 -08001428
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001429 op = SkRegion::kReplace_Op;
1430 }
1431
reed73e714e2014-09-04 09:02:23 -07001432 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433}
1434
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001435void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001436 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001437 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001438}
1439
1440void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001441 AutoValidateClip avc(this);
1442
reed@android.com8a1c16f2008-12-17 15:59:43 +00001443 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001444 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001445
reed@google.com5c3d1472011-02-22 19:12:23 +00001446 // todo: signal fClipStack that we have a region, and therefore (I guess)
1447 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001448 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001449
reed1f836ee2014-07-07 07:49:34 -07001450 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001451}
1452
reed@google.com819c9212011-02-23 18:56:55 +00001453#ifdef SK_DEBUG
1454void SkCanvas::validateClip() const {
1455 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001456 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001457 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001458 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001459 return;
1460 }
1461
reed@google.com819c9212011-02-23 18:56:55 +00001462 SkIRect ir;
1463 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001464 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001465
reed687fa1c2015-04-07 08:00:56 -07001466 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001467 const SkClipStack::Element* element;
1468 while ((element = iter.next()) != NULL) {
1469 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001470 case SkClipStack::Element::kRect_Type:
1471 element->getRect().round(&ir);
1472 tmpClip.op(ir, element->getOp());
1473 break;
1474 case SkClipStack::Element::kEmpty_Type:
1475 tmpClip.setEmpty();
1476 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001477 default: {
1478 SkPath path;
1479 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001480 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001481 break;
1482 }
reed@google.com819c9212011-02-23 18:56:55 +00001483 }
1484 }
reed@google.com819c9212011-02-23 18:56:55 +00001485}
1486#endif
1487
reed@google.com90c07ea2012-04-13 13:50:27 +00001488void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001489 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001490 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001491
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001492 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001493 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001494 }
1495}
1496
reed@google.com5c3d1472011-02-22 19:12:23 +00001497///////////////////////////////////////////////////////////////////////////////
1498
reed@google.com754de5f2014-02-24 19:38:20 +00001499bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001500 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001501}
1502
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001503bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001504 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001505}
1506
reed@google.com3b3e8952012-08-16 20:53:31 +00001507bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001508 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001509 return true;
1510
reed1f836ee2014-07-07 07:49:34 -07001511 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001512 return true;
1513 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001514
reed1f836ee2014-07-07 07:49:34 -07001515 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001516 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001517 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001518 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001519 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001520 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001521
reed@android.coma380ae42009-07-21 01:17:02 +00001522 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001523 // TODO: should we use | instead, or compare all 4 at once?
1524 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001525 return true;
1526 }
reed@google.comc0784db2013-12-13 21:16:12 +00001527 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001528 return true;
1529 }
1530 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001531 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001532}
1533
reed@google.com3b3e8952012-08-16 20:53:31 +00001534bool SkCanvas::quickReject(const SkPath& path) const {
1535 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001536}
1537
reed@google.com3b3e8952012-08-16 20:53:31 +00001538bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001539 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001540 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001541 return false;
1542 }
1543
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001544 SkMatrix inverse;
1545 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001546 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001547 if (bounds) {
1548 bounds->setEmpty();
1549 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001550 return false;
1551 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001552
bsalomon49f085d2014-09-05 13:34:00 -07001553 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001554 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001555 // adjust it outwards in case we are antialiasing
1556 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001557
reed@google.com8f4d2302013-12-17 16:44:46 +00001558 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1559 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001560 inverse.mapRect(bounds, r);
1561 }
1562 return true;
1563}
1564
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001565bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001566 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001567 if (clip.isEmpty()) {
1568 if (bounds) {
1569 bounds->setEmpty();
1570 }
1571 return false;
1572 }
1573
bsalomon49f085d2014-09-05 13:34:00 -07001574 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001575 *bounds = clip.getBounds();
1576 }
1577 return true;
1578}
1579
reed@android.com8a1c16f2008-12-17 15:59:43 +00001580const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001581 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001582}
1583
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001584const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001585 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001586}
1587
reed@google.com9c135db2014-03-12 18:28:35 +00001588GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1589 SkBaseDevice* dev = this->getTopDevice();
1590 return dev ? dev->accessRenderTarget() : NULL;
1591}
1592
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001593GrContext* SkCanvas::getGrContext() {
1594#if SK_SUPPORT_GPU
1595 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001596 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001597 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001598 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001599 return renderTarget->getContext();
1600 }
1601 }
1602#endif
1603
1604 return NULL;
1605
1606}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001607
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001608void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1609 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001610 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001611 if (outer.isEmpty()) {
1612 return;
1613 }
1614 if (inner.isEmpty()) {
1615 this->drawRRect(outer, paint);
1616 return;
1617 }
1618
1619 // We don't have this method (yet), but technically this is what we should
1620 // be able to assert...
1621 // SkASSERT(outer.contains(inner));
1622 //
1623 // For now at least check for containment of bounds
1624 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1625
1626 this->onDrawDRRect(outer, inner, paint);
1627}
1628
reed41af9662015-01-05 07:49:08 -08001629// These need to stop being virtual -- clients need to override the onDraw... versions
1630
1631void SkCanvas::drawPaint(const SkPaint& paint) {
1632 this->onDrawPaint(paint);
1633}
1634
1635void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1636 this->onDrawRect(r, paint);
1637}
1638
1639void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1640 this->onDrawOval(r, paint);
1641}
1642
1643void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1644 this->onDrawRRect(rrect, paint);
1645}
1646
1647void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1648 this->onDrawPoints(mode, count, pts, paint);
1649}
1650
1651void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1652 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1653 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1654 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1655 indices, indexCount, paint);
1656}
1657
1658void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1659 this->onDrawPath(path, paint);
1660}
1661
1662void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1663 this->onDrawImage(image, dx, dy, paint);
1664}
1665
1666void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1667 const SkPaint* paint) {
1668 this->onDrawImageRect(image, src, dst, paint);
1669}
1670
1671void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1672 this->onDrawBitmap(bitmap, dx, dy, paint);
1673}
1674
1675void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1676 const SkPaint* paint, DrawBitmapRectFlags flags) {
1677 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1678}
1679
1680void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1681 const SkPaint* paint) {
1682 this->onDrawBitmapNine(bitmap, center, dst, paint);
1683}
1684
1685void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
1686 this->onDrawSprite(bitmap, left, top, paint);
1687}
1688
reed@android.com8a1c16f2008-12-17 15:59:43 +00001689//////////////////////////////////////////////////////////////////////////////
1690// These are the virtual drawing methods
1691//////////////////////////////////////////////////////////////////////////////
1692
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001693void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001694 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001695 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1696 }
1697}
1698
reed41af9662015-01-05 07:49:08 -08001699void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001700 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001701 this->internalDrawPaint(paint);
1702}
1703
1704void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001705 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001706
1707 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001708 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001709 }
1710
reed@google.com4e2b3d32011-04-07 14:18:59 +00001711 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001712}
1713
reed41af9662015-01-05 07:49:08 -08001714void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1715 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001716 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001717 if ((long)count <= 0) {
1718 return;
1719 }
1720
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001721 SkRect r, storage;
1722 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001723 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001724 // special-case 2 points (common for drawing a single line)
1725 if (2 == count) {
1726 r.set(pts[0], pts[1]);
1727 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001728 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001729 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001730 bounds = &paint.computeFastStrokeBounds(r, &storage);
1731 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001732 return;
1733 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001734 }
reed@google.coma584aed2012-05-16 14:06:02 +00001735
reed@android.com8a1c16f2008-12-17 15:59:43 +00001736 SkASSERT(pts != NULL);
1737
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001738 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001739
reed@android.com8a1c16f2008-12-17 15:59:43 +00001740 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001741 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001742 }
reed@google.com4b226022011-01-11 18:32:13 +00001743
reed@google.com4e2b3d32011-04-07 14:18:59 +00001744 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001745}
1746
reed41af9662015-01-05 07:49:08 -08001747void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001748 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001749 SkRect storage;
1750 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001751 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001752 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1753 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1754 SkRect tmp(r);
1755 tmp.sort();
1756
1757 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001758 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001759 return;
1760 }
1761 }
reed@google.com4b226022011-01-11 18:32:13 +00001762
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001763 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001764
1765 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001766 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001767 }
1768
reed@google.com4e2b3d32011-04-07 14:18:59 +00001769 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001770}
1771
reed41af9662015-01-05 07:49:08 -08001772void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001773 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001774 SkRect storage;
1775 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001776 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001777 bounds = &paint.computeFastBounds(oval, &storage);
1778 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001779 return;
1780 }
1781 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001782
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001783 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001784
1785 while (iter.next()) {
1786 iter.fDevice->drawOval(iter, oval, looper.paint());
1787 }
1788
1789 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001790}
1791
reed41af9662015-01-05 07:49:08 -08001792void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001793 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001794 SkRect storage;
1795 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001796 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001797 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1798 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001799 return;
1800 }
1801 }
1802
1803 if (rrect.isRect()) {
1804 // call the non-virtual version
1805 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001806 return;
1807 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001808 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001809 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1810 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001811 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001812
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001813 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001814
1815 while (iter.next()) {
1816 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1817 }
1818
1819 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001820}
1821
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001822void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1823 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001824 SkRect storage;
1825 const SkRect* bounds = NULL;
1826 if (paint.canComputeFastBounds()) {
1827 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1828 if (this->quickReject(*bounds)) {
1829 return;
1830 }
1831 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001832
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001833 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001834
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001835 while (iter.next()) {
1836 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1837 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001838
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001839 LOOPER_END
1840}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001841
reed41af9662015-01-05 07:49:08 -08001842void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001843 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001844 if (!path.isFinite()) {
1845 return;
1846 }
1847
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001848 SkRect storage;
1849 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001850 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001851 const SkRect& pathBounds = path.getBounds();
1852 bounds = &paint.computeFastBounds(pathBounds, &storage);
1853 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001854 return;
1855 }
1856 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001857
1858 const SkRect& r = path.getBounds();
1859 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001860 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001861 this->internalDrawPaint(paint);
1862 }
1863 return;
1864 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001865
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001866 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001867
1868 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001869 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001870 }
1871
reed@google.com4e2b3d32011-04-07 14:18:59 +00001872 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001873}
1874
kkinnunena9baa652015-03-05 06:33:54 -08001875void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001876 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
kkinnunena9baa652015-03-05 06:33:54 -08001877 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001878}
1879
reed41af9662015-01-05 07:49:08 -08001880void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1881 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001882 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
kkinnunena9baa652015-03-05 06:33:54 -08001883 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001884}
1885
reed41af9662015-01-05 07:49:08 -08001886void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001887 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001888 SkDEBUGCODE(bitmap.validate();)
1889
reed@google.com3d608122011-11-21 15:16:16 +00001890 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001891 SkRect bounds = {
1892 x, y,
1893 x + SkIntToScalar(bitmap.width()),
1894 y + SkIntToScalar(bitmap.height())
1895 };
1896 if (paint) {
1897 (void)paint->computeFastBounds(bounds, &bounds);
1898 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001899 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001900 return;
1901 }
1902 }
reed@google.com4b226022011-01-11 18:32:13 +00001903
reed@android.com8a1c16f2008-12-17 15:59:43 +00001904 SkMatrix matrix;
1905 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001906 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001907}
1908
reed@google.com9987ec32011-09-07 11:57:52 +00001909// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00001910void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001911 const SkRect& dst, const SkPaint* paint,
1912 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001913 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001914 return;
1915 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001916
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001917 SkRect storage;
1918 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00001919 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001920 if (paint) {
1921 bounds = &paint->computeFastBounds(dst, &storage);
1922 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001923 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001924 return;
1925 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001926 }
reed@google.com3d608122011-11-21 15:16:16 +00001927
reed@google.com33535f32012-09-25 15:37:50 +00001928 SkLazyPaint lazy;
1929 if (NULL == paint) {
1930 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001931 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001932
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001933 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001934
reed@google.com33535f32012-09-25 15:37:50 +00001935 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001936 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00001937 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001938
reed@google.com33535f32012-09-25 15:37:50 +00001939 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001940}
1941
reed41af9662015-01-05 07:49:08 -08001942void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1943 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08001944 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00001945 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001946 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00001947}
1948
reed@google.com9987ec32011-09-07 11:57:52 +00001949void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1950 const SkIRect& center, const SkRect& dst,
1951 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001952 if (bitmap.drawsNothing()) {
1953 return;
1954 }
reed@google.com3d608122011-11-21 15:16:16 +00001955 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00001956 SkRect storage;
1957 const SkRect* bounds = &dst;
1958 if (paint) {
1959 bounds = &paint->computeFastBounds(dst, &storage);
1960 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001961 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001962 return;
1963 }
1964 }
1965
reed@google.com9987ec32011-09-07 11:57:52 +00001966 const int32_t w = bitmap.width();
1967 const int32_t h = bitmap.height();
1968
1969 SkIRect c = center;
1970 // pin center to the bounds of the bitmap
1971 c.fLeft = SkMax32(0, center.fLeft);
1972 c.fTop = SkMax32(0, center.fTop);
1973 c.fRight = SkPin32(center.fRight, c.fLeft, w);
1974 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1975
reed@google.com71121732012-09-18 15:14:33 +00001976 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001977 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00001978 };
1979 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00001980 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00001981 };
reed@google.com9987ec32011-09-07 11:57:52 +00001982 SkScalar dstX[4] = {
1983 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
1984 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
1985 };
1986 SkScalar dstY[4] = {
1987 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
1988 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
1989 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001990
reed@google.com9987ec32011-09-07 11:57:52 +00001991 if (dstX[1] > dstX[2]) {
1992 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
1993 dstX[2] = dstX[1];
1994 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001995
reed@google.com9987ec32011-09-07 11:57:52 +00001996 if (dstY[1] > dstY[2]) {
1997 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
1998 dstY[2] = dstY[1];
1999 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002000
reed@google.com9987ec32011-09-07 11:57:52 +00002001 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00002002 SkRect s, d;
2003
reed@google.com9987ec32011-09-07 11:57:52 +00002004 s.fTop = srcY[y];
2005 s.fBottom = srcY[y+1];
2006 d.fTop = dstY[y];
2007 d.fBottom = dstY[y+1];
2008 for (int x = 0; x < 3; x++) {
2009 s.fLeft = srcX[x];
2010 s.fRight = srcX[x+1];
2011 d.fLeft = dstX[x];
2012 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002013 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00002014 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00002015 }
2016 }
2017}
2018
reed41af9662015-01-05 07:49:08 -08002019void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2020 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002021 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002022 SkDEBUGCODE(bitmap.validate();)
2023
2024 // Need a device entry-point, so gpu can use a mesh
2025 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2026}
2027
reed@google.comf67e4cf2011-03-15 20:56:58 +00002028class SkDeviceFilteredPaint {
2029public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002030 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002031 uint32_t filteredFlags = device->filterTextFlags(paint);
2032 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002033 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002034 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002035 fPaint = newPaint;
2036 } else {
2037 fPaint = &paint;
2038 }
2039 }
2040
reed@google.comf67e4cf2011-03-15 20:56:58 +00002041 const SkPaint& paint() const { return *fPaint; }
2042
2043private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002044 const SkPaint* fPaint;
2045 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002046};
2047
bungeman@google.com52c748b2011-08-22 21:30:43 +00002048void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2049 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002050 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002051 draw.fDevice->drawRect(draw, r, paint);
2052 } else {
2053 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002054 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002055 draw.fDevice->drawRect(draw, r, p);
2056 }
2057}
2058
2059void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2060 const char text[], size_t byteLength,
2061 SkScalar x, SkScalar y) {
2062 SkASSERT(byteLength == 0 || text != NULL);
2063
2064 // nothing to draw
2065 if (text == NULL || byteLength == 0 ||
2066 draw.fClip->isEmpty() ||
2067 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2068 return;
2069 }
2070
2071 SkScalar width = 0;
2072 SkPoint start;
2073
2074 start.set(0, 0); // to avoid warning
2075 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2076 SkPaint::kStrikeThruText_Flag)) {
2077 width = paint.measureText(text, byteLength);
2078
2079 SkScalar offsetX = 0;
2080 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2081 offsetX = SkScalarHalf(width);
2082 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2083 offsetX = width;
2084 }
2085 start.set(x - offsetX, y);
2086 }
2087
2088 if (0 == width) {
2089 return;
2090 }
2091
2092 uint32_t flags = paint.getFlags();
2093
2094 if (flags & (SkPaint::kUnderlineText_Flag |
2095 SkPaint::kStrikeThruText_Flag)) {
2096 SkScalar textSize = paint.getTextSize();
2097 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2098 SkRect r;
2099
2100 r.fLeft = start.fX;
2101 r.fRight = start.fX + width;
2102
2103 if (flags & SkPaint::kUnderlineText_Flag) {
2104 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2105 start.fY);
2106 r.fTop = offset;
2107 r.fBottom = offset + height;
2108 DrawRect(draw, paint, r, textSize);
2109 }
2110 if (flags & SkPaint::kStrikeThruText_Flag) {
2111 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2112 start.fY);
2113 r.fTop = offset;
2114 r.fBottom = offset + height;
2115 DrawRect(draw, paint, r, textSize);
2116 }
2117 }
2118}
2119
reed@google.come0d9ce82014-04-23 04:00:17 +00002120void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2121 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002122 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002123
2124 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002125 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002126 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002127 DrawTextDecorations(iter, dfp.paint(),
2128 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002129 }
2130
reed@google.com4e2b3d32011-04-07 14:18:59 +00002131 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002132}
2133
reed@google.come0d9ce82014-04-23 04:00:17 +00002134void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2135 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002136 SkPoint textOffset = SkPoint::Make(0, 0);
2137
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002138 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002139
reed@android.com8a1c16f2008-12-17 15:59:43 +00002140 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002141 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002142 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002143 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002144 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002145
reed@google.com4e2b3d32011-04-07 14:18:59 +00002146 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002147}
2148
reed@google.come0d9ce82014-04-23 04:00:17 +00002149void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2150 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002151
2152 SkPoint textOffset = SkPoint::Make(0, constY);
2153
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002154 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002155
reed@android.com8a1c16f2008-12-17 15:59:43 +00002156 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002157 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002158 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002159 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002160 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002161
reed@google.com4e2b3d32011-04-07 14:18:59 +00002162 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002163}
2164
reed@google.come0d9ce82014-04-23 04:00:17 +00002165void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2166 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002167 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002168
reed@android.com8a1c16f2008-12-17 15:59:43 +00002169 while (iter.next()) {
2170 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002171 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002172 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002173
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002174 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002175}
2176
fmalita00d5c2c2014-08-21 08:53:26 -07002177void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2178 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002179
fmalita85d5eb92015-03-04 11:20:12 -08002180 SkRect storage;
2181 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002182 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002183 storage = blob->bounds().makeOffset(x, y);
2184 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002185
fmalita85d5eb92015-03-04 11:20:12 -08002186 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002187 return;
2188 }
2189 }
2190
fmalita024f9962015-03-03 19:08:17 -08002191 // We cannot filter in the looper as we normally do, because the paint is
2192 // incomplete at this point (text-related attributes are embedded within blob run paints).
2193 SkDrawFilter* drawFilter = fMCRec->fFilter;
2194 fMCRec->fFilter = NULL;
2195
fmalita85d5eb92015-03-04 11:20:12 -08002196 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002197
fmalitaaa1b9122014-08-28 14:32:24 -07002198 while (iter.next()) {
2199 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002200 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002201 }
2202
fmalitaaa1b9122014-08-28 14:32:24 -07002203 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002204
2205 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002206}
2207
reed@google.come0d9ce82014-04-23 04:00:17 +00002208// These will become non-virtual, so they always call the (virtual) onDraw... method
2209void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2210 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002211 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002212 this->onDrawText(text, byteLength, x, y, paint);
2213}
2214void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2215 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002216 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002217 this->onDrawPosText(text, byteLength, pos, paint);
2218}
2219void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2220 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002221 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002222 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2223}
2224void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2225 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002226 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002227 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2228}
fmalita00d5c2c2014-08-21 08:53:26 -07002229void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2230 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002231 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002232 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002233 this->onDrawTextBlob(blob, x, y, paint);
2234 }
2235}
reed@google.come0d9ce82014-04-23 04:00:17 +00002236
reed41af9662015-01-05 07:49:08 -08002237void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2238 const SkPoint verts[], const SkPoint texs[],
2239 const SkColor colors[], SkXfermode* xmode,
2240 const uint16_t indices[], int indexCount,
2241 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002242 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002243 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002244
reed@android.com8a1c16f2008-12-17 15:59:43 +00002245 while (iter.next()) {
2246 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002247 colors, xmode, indices, indexCount,
2248 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002249 }
reed@google.com4b226022011-01-11 18:32:13 +00002250
reed@google.com4e2b3d32011-04-07 14:18:59 +00002251 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002252}
2253
dandovb3c9d1c2014-08-12 08:34:29 -07002254void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2255 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002256 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002257 if (NULL == cubics) {
2258 return;
2259 }
mtklein6cfa73a2014-08-13 13:33:49 -07002260
dandovecfff212014-08-04 10:02:00 -07002261 // Since a patch is always within the convex hull of the control points, we discard it when its
2262 // bounding rectangle is completely outside the current clip.
2263 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002264 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002265 if (this->quickReject(bounds)) {
2266 return;
2267 }
mtklein6cfa73a2014-08-13 13:33:49 -07002268
dandovb3c9d1c2014-08-12 08:34:29 -07002269 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2270}
2271
2272void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2273 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2274
dandovecfff212014-08-04 10:02:00 -07002275 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002276
dandovecfff212014-08-04 10:02:00 -07002277 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002278 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002279 }
mtklein6cfa73a2014-08-13 13:33:49 -07002280
dandovecfff212014-08-04 10:02:00 -07002281 LOOPER_END
2282}
2283
reed3cb38402015-02-06 08:36:15 -08002284void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002285 if (dr && !this->quickReject(dr->getBounds())) {
2286 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002287 }
2288}
2289
reed3cb38402015-02-06 08:36:15 -08002290void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002291 dr->draw(this);
2292}
2293
reed@android.com8a1c16f2008-12-17 15:59:43 +00002294//////////////////////////////////////////////////////////////////////////////
2295// These methods are NOT virtual, and therefore must call back into virtual
2296// methods, rather than actually drawing themselves.
2297//////////////////////////////////////////////////////////////////////////////
2298
2299void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002300 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002301 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302 SkPaint paint;
2303
2304 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002305 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002306 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307 }
2308 this->drawPaint(paint);
2309}
2310
reed@android.com845fdac2009-06-23 03:01:32 +00002311void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002312 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002313 SkPaint paint;
2314
2315 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002316 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002317 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318 }
2319 this->drawPaint(paint);
2320}
2321
2322void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002323 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002325
reed@android.com8a1c16f2008-12-17 15:59:43 +00002326 pt.set(x, y);
2327 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2328}
2329
2330void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002331 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002332 SkPoint pt;
2333 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002334
reed@android.com8a1c16f2008-12-17 15:59:43 +00002335 pt.set(x, y);
2336 paint.setColor(color);
2337 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2338}
2339
2340void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2341 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002342 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002343 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002344
reed@android.com8a1c16f2008-12-17 15:59:43 +00002345 pts[0].set(x0, y0);
2346 pts[1].set(x1, y1);
2347 this->drawPoints(kLines_PointMode, 2, pts, paint);
2348}
2349
2350void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2351 SkScalar right, SkScalar bottom,
2352 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002353 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002354 SkRect r;
2355
2356 r.set(left, top, right, bottom);
2357 this->drawRect(r, paint);
2358}
2359
2360void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2361 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002362 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002363 if (radius < 0) {
2364 radius = 0;
2365 }
2366
2367 SkRect r;
2368 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002369 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002370}
2371
2372void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2373 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002374 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002375 if (rx > 0 && ry > 0) {
2376 if (paint.canComputeFastBounds()) {
2377 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002378 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002379 return;
2380 }
2381 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002382 SkRRect rrect;
2383 rrect.setRectXY(r, rx, ry);
2384 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002385 } else {
2386 this->drawRect(r, paint);
2387 }
2388}
2389
reed@android.com8a1c16f2008-12-17 15:59:43 +00002390void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2391 SkScalar sweepAngle, bool useCenter,
2392 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002393 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002394 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2395 this->drawOval(oval, paint);
2396 } else {
2397 SkPath path;
2398 if (useCenter) {
2399 path.moveTo(oval.centerX(), oval.centerY());
2400 }
2401 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2402 if (useCenter) {
2403 path.close();
2404 }
2405 this->drawPath(path, paint);
2406 }
2407}
2408
2409void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2410 const SkPath& path, SkScalar hOffset,
2411 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002412 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002413 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002414
reed@android.com8a1c16f2008-12-17 15:59:43 +00002415 matrix.setTranslate(hOffset, vOffset);
2416 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2417}
2418
reed@android.comf76bacf2009-05-13 14:00:33 +00002419///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002420void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002421 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002422 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002423 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002424 }
2425}
2426
reedd5fa1a42014-08-09 11:08:05 -07002427void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002428 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002429 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002430 if (matrix && matrix->isIdentity()) {
2431 matrix = NULL;
2432 }
2433 this->onDrawPicture(picture, matrix, paint);
2434 }
2435}
robertphillips9b14f262014-06-04 05:40:44 -07002436
reedd5fa1a42014-08-09 11:08:05 -07002437void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2438 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002439 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002440 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002441 // Canvas has to first give the device the opportunity to render
2442 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002443 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002444 return; // the device has rendered the entire picture
2445 }
2446 }
2447
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002448 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002449
robertphillipsc5ba71d2014-09-04 08:42:50 -07002450 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002451}
2452
reed@android.com8a1c16f2008-12-17 15:59:43 +00002453///////////////////////////////////////////////////////////////////////////////
2454///////////////////////////////////////////////////////////////////////////////
2455
2456SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002457 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002458
2459 SkASSERT(canvas);
2460
2461 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2462 fDone = !fImpl->next();
2463}
2464
2465SkCanvas::LayerIter::~LayerIter() {
2466 fImpl->~SkDrawIter();
2467}
2468
2469void SkCanvas::LayerIter::next() {
2470 fDone = !fImpl->next();
2471}
2472
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002473SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002474 return fImpl->getDevice();
2475}
2476
2477const SkMatrix& SkCanvas::LayerIter::matrix() const {
2478 return fImpl->getMatrix();
2479}
2480
2481const SkPaint& SkCanvas::LayerIter::paint() const {
2482 const SkPaint* paint = fImpl->getPaint();
2483 if (NULL == paint) {
2484 paint = &fDefaultPaint;
2485 }
2486 return *paint;
2487}
2488
2489const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2490int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2491int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002492
2493///////////////////////////////////////////////////////////////////////////////
2494
fmalitac3b589a2014-06-05 12:40:07 -07002495SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002496
2497///////////////////////////////////////////////////////////////////////////////
2498
2499static bool supported_for_raster_canvas(const SkImageInfo& info) {
2500 switch (info.alphaType()) {
2501 case kPremul_SkAlphaType:
2502 case kOpaque_SkAlphaType:
2503 break;
2504 default:
2505 return false;
2506 }
2507
2508 switch (info.colorType()) {
2509 case kAlpha_8_SkColorType:
2510 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002511 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002512 break;
2513 default:
2514 return false;
2515 }
2516
2517 return true;
2518}
2519
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002520SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2521 if (!supported_for_raster_canvas(info)) {
2522 return NULL;
2523 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002524
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002525 SkBitmap bitmap;
2526 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2527 return NULL;
2528 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002529 return SkNEW_ARGS(SkCanvas, (bitmap));
2530}
reedd5fa1a42014-08-09 11:08:05 -07002531
2532///////////////////////////////////////////////////////////////////////////////
2533
2534SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002535 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002536 : fCanvas(canvas)
2537 , fSaveCount(canvas->getSaveCount())
2538{
bsalomon49f085d2014-09-05 13:34:00 -07002539 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002540 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002541 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002542 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002543 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002544 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002545 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002546 canvas->save();
2547 }
mtklein6cfa73a2014-08-13 13:33:49 -07002548
bsalomon49f085d2014-09-05 13:34:00 -07002549 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002550 canvas->concat(*matrix);
2551 }
2552}
2553
2554SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2555 fCanvas->restoreToCount(fSaveCount);
2556}