blob: 0bd9eb357944bf4de88f101f68382cbf68ecab07 [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();
reed5c476fb2015-04-20 08:04:21 -0700311 fTempLayerForImageFilter = 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()) {
reed5c476fb2015-04-20 08:04:21 -0700315 /**
316 * We implement ImageFilters for a given draw by creating a layer, then applying the
317 * imagefilter to the pixels of that layer (its backing surface/image), and then
318 * we call restore() to xfer that layer to the main canvas.
319 *
320 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
321 * 2. Generate the src pixels:
322 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
323 * return (fPaint). We then draw the primitive (using srcover) into a cleared
324 * buffer/surface.
325 * 3. Restore the layer created in #1
326 * The imagefilter is passed the buffer/surface from the layer (now filled with the
327 * src pixels of the primitive). It returns a new "filtered" buffer, which we
328 * draw onto the previous layer using the xfermode from the original paint.
329 */
reed@google.com8926b162012-03-23 15:36:36 +0000330 SkPaint tmp;
reed1b110d62015-03-08 18:47:13 -0700331 tmp.setImageFilter(fOrigPaint.getImageFilter());
reed5c476fb2015-04-20 08:04:21 -0700332 tmp.setXfermode(fOrigPaint.getXfermode());
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000333 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
reed76033be2015-03-14 10:54:31 -0700334 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700335 fTempLayerForImageFilter = true;
336 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000337 }
338
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000339 if (SkDrawLooper* looper = paint.getLooper()) {
340 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
341 looper->contextSize());
342 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000343 fIsSimple = false;
344 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000345 fLooperContext = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000346 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700347 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000348 }
piotaixrb5fae932014-09-24 13:03:30 -0700349
reed4a8126e2014-09-22 07:29:03 -0700350 uint32_t oldFlags = paint.getFlags();
351 fNewPaintFlags = filter_paint_flags(props, oldFlags);
352 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reed1b110d62015-03-08 18:47:13 -0700353 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700354 paint->setFlags(fNewPaintFlags);
355 fPaint = paint;
356 // if we're not simple, doNext() will take care of calling setFlags()
357 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000358 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000359
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700361 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000362 fCanvas->internalRestore();
363 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000364 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000366
reed@google.com4e2b3d32011-04-07 14:18:59 +0000367 const SkPaint& paint() const {
368 SkASSERT(fPaint);
369 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000371
reed@google.com129ec222012-05-15 13:24:09 +0000372 bool next(SkDrawFilter::Type drawType) {
373 if (fDone) {
374 return false;
375 } else if (fIsSimple) {
376 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000377 return !fPaint->nothingToDraw();
378 } else {
379 return this->doNext(drawType);
380 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000381 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000382
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383private:
reed1b110d62015-03-08 18:47:13 -0700384 SkLazyPaint fLazyPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000385 SkCanvas* fCanvas;
386 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000387 SkDrawFilter* fFilter;
388 const SkPaint* fPaint;
389 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700390 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700391 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000392 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000393 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000394 SkDrawLooper::Context* fLooperContext;
395 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000396
397 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000398};
399
reed@google.com129ec222012-05-15 13:24:09 +0000400bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
reed@google.com632e1a22011-10-06 12:37:00 +0000401 fPaint = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000402 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700403 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000404
reed1b110d62015-03-08 18:47:13 -0700405 SkPaint* paint = fLazyPaint.set(fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700406 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000407
reed5c476fb2015-04-20 08:04:21 -0700408 if (fTempLayerForImageFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000409 paint->setImageFilter(NULL);
reed5c476fb2015-04-20 08:04:21 -0700410 paint->setXfermode(NULL);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000411 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000412
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000413 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000414 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000415 return false;
416 }
417 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000418 if (!fFilter->filter(paint, drawType)) {
419 fDone = true;
420 return false;
421 }
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000422 if (NULL == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000423 // no looper means we only draw once
424 fDone = true;
425 }
426 }
427 fPaint = paint;
428
429 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000430 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000431 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000432 }
433
434 // call this after any possible paint modifiers
435 if (fPaint->nothingToDraw()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000436 fPaint = NULL;
437 return false;
438 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000439 return true;
440}
441
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442////////// macros to place around the internal draw calls //////////////////
443
reed@google.com8926b162012-03-23 15:36:36 +0000444#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000445 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700446 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000447 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000448 SkDrawIter iter(this);
449
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000450#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000451 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700452 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000453 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000455
reed@google.com4e2b3d32011-04-07 14:18:59 +0000456#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000457
458////////////////////////////////////////////////////////////////////////////
459
mtkleinfeaadee2015-04-08 11:25:48 -0700460void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
461 this->restoreToCount(1);
462 fCachedLocalClipBounds.setEmpty();
463 fCachedLocalClipBoundsDirty = true;
464 fClipStack->reset();
465 fMCRec->reset(bounds);
466
467 // We're peering through a lot of structs here. Only at this scope do we
468 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
469 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
470}
471
reedd9544982014-09-09 18:46:22 -0700472SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
473 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
reed@google.comc0784db2013-12-13 21:16:12 +0000474 fCachedLocalClipBounds.setEmpty();
475 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000476 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000477 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700478 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800479 fSaveCount = 1;
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000480 fMetaData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000481
reed687fa1c2015-04-07 08:00:56 -0700482 fClipStack.reset(SkNEW(SkClipStack));
483
reed@android.com8a1c16f2008-12-17 15:59:43 +0000484 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700485 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000486
reedb679ca82015-04-07 04:40:48 -0700487 SkASSERT(sizeof(DeviceCM) <= sizeof(fBaseLayerStorage));
488 fMCRec->fLayer = (DeviceCM*)fBaseLayerStorage;
489 new (fBaseLayerStorage) DeviceCM(NULL, NULL, NULL, fConservativeRasterClip);
490
reed@android.com8a1c16f2008-12-17 15:59:43 +0000491 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000492
reed@google.com97af1a62012-08-28 12:19:02 +0000493 fSurfaceBase = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000494
reedf92c8662014-08-18 08:02:43 -0700495 if (device) {
reedb2db8982014-11-13 12:41:02 -0800496 device->initForRootLayer(fProps.pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700497 if (device->forceConservativeRasterClip()) {
498 fConservativeRasterClip = true;
499 }
reedf92c8662014-08-18 08:02:43 -0700500 device->onAttachToCanvas(this);
501 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800502 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700503 }
504 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000505}
506
reed@google.comcde92112011-07-06 20:00:52 +0000507SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000508 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700509 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000510{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000511 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000512
reedd9544982014-09-09 18:46:22 -0700513 this->init(NULL, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000514}
515
reedd9544982014-09-09 18:46:22 -0700516static SkBitmap make_nopixels(int width, int height) {
517 SkBitmap bitmap;
518 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
519 return bitmap;
520}
521
522class SkNoPixelsBitmapDevice : public SkBitmapDevice {
523public:
reed78e27682014-11-19 08:04:34 -0800524 SkNoPixelsBitmapDevice(const SkIRect& bounds)
525 : INHERITED(make_nopixels(bounds.width(), bounds.height()))
526 {
527 this->setOrigin(bounds.x(), bounds.y());
528 }
reedd9544982014-09-09 18:46:22 -0700529
530private:
piotaixrb5fae932014-09-24 13:03:30 -0700531
reedd9544982014-09-09 18:46:22 -0700532 typedef SkBitmapDevice INHERITED;
533};
534
reed96a857e2015-01-25 10:33:58 -0800535SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000536 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800537 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000538{
539 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700540
reed78e27682014-11-19 08:04:34 -0800541 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
542 (SkIRect::MakeWH(width, height))), kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700543}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000544
reed78e27682014-11-19 08:04:34 -0800545SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700546 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700547 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700548{
549 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700550
reed78e27682014-11-19 08:04:34 -0800551 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds)), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700552}
553
reed4a8126e2014-09-22 07:29:03 -0700554SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700555 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700556 , fProps(SkSurfacePropsCopyOrDefault(props))
reedd9544982014-09-09 18:46:22 -0700557{
558 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700559
reedd9544982014-09-09 18:46:22 -0700560 this->init(device, flags);
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000561}
562
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000563SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000564 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700565 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000566{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000567 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700568
reedd9544982014-09-09 18:46:22 -0700569 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000570}
571
reed4a8126e2014-09-22 07:29:03 -0700572SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700573 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700574 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700575{
576 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700577
reed4a8126e2014-09-22 07:29:03 -0700578 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
579 this->init(device, kDefault_InitFlags);
580}
reed29c857d2014-09-21 10:25:07 -0700581
reed4a8126e2014-09-22 07:29:03 -0700582SkCanvas::SkCanvas(const SkBitmap& bitmap)
583 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
584 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
585{
586 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700587
reed4a8126e2014-09-22 07:29:03 -0700588 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
589 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000590}
591
592SkCanvas::~SkCanvas() {
593 // free up the contents of our deque
594 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000595
reed@android.com8a1c16f2008-12-17 15:59:43 +0000596 this->internalRestore(); // restore the last, since we're going away
597
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000598 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000599
reed@android.com8a1c16f2008-12-17 15:59:43 +0000600 dec_canvas();
601}
602
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603SkDrawFilter* SkCanvas::getDrawFilter() const {
604 return fMCRec->fFilter;
605}
606
607SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700608 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000609 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
610 return filter;
611}
612
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000613SkMetaData& SkCanvas::getMetaData() {
614 // metadata users are rare, so we lazily allocate it. If that changes we
615 // can decide to just make it a field in the device (rather than a ptr)
616 if (NULL == fMetaData) {
617 fMetaData = new SkMetaData;
618 }
619 return *fMetaData;
620}
621
reed@android.com8a1c16f2008-12-17 15:59:43 +0000622///////////////////////////////////////////////////////////////////////////////
623
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000624void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000625 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000626 if (device) {
627 device->flush();
628 }
629}
630
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000631SkISize SkCanvas::getTopLayerSize() const {
632 SkBaseDevice* d = this->getTopDevice();
633 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
634}
635
636SkIPoint SkCanvas::getTopLayerOrigin() const {
637 SkBaseDevice* d = this->getTopDevice();
638 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
639}
640
641SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000642 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000643 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
644}
645
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000646SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000648 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000649 SkASSERT(rec && rec->fLayer);
650 return rec->fLayer->fDevice;
651}
652
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000653SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000654 if (updateMatrixClip) {
655 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
656 }
reed@google.com9266fed2011-03-30 00:18:03 +0000657 return fMCRec->fTopLayer->fDevice;
658}
659
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000660bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
661 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
662 return false;
663 }
664
665 bool weAllocated = false;
666 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700667 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000668 return false;
669 }
670 weAllocated = true;
671 }
672
673 SkBitmap bm(*bitmap);
674 bm.lockPixels();
675 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
676 return true;
677 }
678
679 if (weAllocated) {
680 bitmap->setPixelRef(NULL);
681 }
682 return false;
683}
reed@google.com51df9e32010-12-23 19:29:18 +0000684
bsalomon@google.comc6980972011-11-02 19:57:21 +0000685bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000686 SkIRect r = srcRect;
687 const SkISize size = this->getBaseLayerSize();
688 if (!r.intersect(0, 0, size.width(), size.height())) {
689 bitmap->reset();
690 return false;
691 }
692
reed84825042014-09-02 12:50:45 -0700693 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000694 // bitmap will already be reset.
695 return false;
696 }
697 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
698 bitmap->reset();
699 return false;
700 }
701 return true;
702}
703
reed96472de2014-12-10 09:53:42 -0800704bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000705 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000706 if (!device) {
707 return false;
708 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000709 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800710
reed96472de2014-12-10 09:53:42 -0800711 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
712 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000713 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000714 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000715
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000716 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800717 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000718}
719
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000720bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
721 if (bitmap.getTexture()) {
722 return false;
723 }
724 SkBitmap bm(bitmap);
725 bm.lockPixels();
726 if (bm.getPixels()) {
727 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
728 }
729 return false;
730}
731
732bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
733 int x, int y) {
734 switch (origInfo.colorType()) {
735 case kUnknown_SkColorType:
736 case kIndex_8_SkColorType:
737 return false;
738 default:
739 break;
740 }
741 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
742 return false;
743 }
744
745 const SkISize size = this->getBaseLayerSize();
746 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
747 if (!target.intersect(0, 0, size.width(), size.height())) {
748 return false;
749 }
750
751 SkBaseDevice* device = this->getDevice();
752 if (!device) {
753 return false;
754 }
755
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000756 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700757 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000758
759 // if x or y are negative, then we have to adjust pixels
760 if (x > 0) {
761 x = 0;
762 }
763 if (y > 0) {
764 y = 0;
765 }
766 // here x,y are either 0 or negative
767 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
768
reed4af35f32014-06-27 17:47:49 -0700769 // Tell our owning surface to bump its generation ID
770 this->predrawNotify();
771
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000772 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000773 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000774}
reed@google.com51df9e32010-12-23 19:29:18 +0000775
junov@google.com4370aed2012-01-18 16:21:08 +0000776SkCanvas* SkCanvas::canvasForDrawIter() {
777 return this;
778}
779
reed@android.com8a1c16f2008-12-17 15:59:43 +0000780//////////////////////////////////////////////////////////////////////////////
781
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782void SkCanvas::updateDeviceCMCache() {
783 if (fDeviceCMDirty) {
784 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700785 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000786 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000787
reed@android.com8a1c16f2008-12-17 15:59:43 +0000788 if (NULL == layer->fNext) { // only one layer
reed687fa1c2015-04-07 08:00:56 -0700789 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000791 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000792 do {
reed687fa1c2015-04-07 08:00:56 -0700793 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000794 } while ((layer = layer->fNext) != NULL);
795 }
796 fDeviceCMDirty = false;
797 }
798}
799
reed@android.com8a1c16f2008-12-17 15:59:43 +0000800///////////////////////////////////////////////////////////////////////////////
801
reed2ff1fce2014-12-11 07:07:37 -0800802void SkCanvas::checkForDeferredSave() {
803 if (fMCRec->fDeferredSaveCount > 0) {
804 fMCRec->fDeferredSaveCount -= 1;
805 this->doSave();
806 }
807}
808
reedf0090cb2014-11-26 08:55:51 -0800809int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800810#ifdef SK_DEBUG
811 int count = 0;
812 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
813 for (;;) {
814 const MCRec* rec = (const MCRec*)iter.next();
815 if (!rec) {
816 break;
817 }
818 count += 1 + rec->fDeferredSaveCount;
819 }
820 SkASSERT(count == fSaveCount);
821#endif
822 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800823}
824
825int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800826 fSaveCount += 1;
827 fMCRec->fDeferredSaveCount += 1;
828 return this->getSaveCount() - 1; // return our prev value
829}
830
831void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800832 this->willSave();
reed2ff1fce2014-12-11 07:07:37 -0800833 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800834}
835
836void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800837 if (fMCRec->fDeferredSaveCount > 0) {
838 SkASSERT(fSaveCount > 1);
839 fSaveCount -= 1;
840 fMCRec->fDeferredSaveCount -= 1;
841 } else {
842 // check for underflow
843 if (fMCStack.count() > 1) {
844 this->willRestore();
845 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700846 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800847 this->internalRestore();
848 this->didRestore();
849 }
reedf0090cb2014-11-26 08:55:51 -0800850 }
851}
852
853void SkCanvas::restoreToCount(int count) {
854 // sanity check
855 if (count < 1) {
856 count = 1;
857 }
mtkleinf0f14112014-12-12 08:46:25 -0800858
reedf0090cb2014-11-26 08:55:51 -0800859 int n = this->getSaveCount() - count;
860 for (int i = 0; i < n; ++i) {
861 this->restore();
862 }
863}
864
reed2ff1fce2014-12-11 07:07:37 -0800865void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000866 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700867 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000868 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000869
reed687fa1c2015-04-07 08:00:56 -0700870 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871}
872
reed@android.com8a1c16f2008-12-17 15:59:43 +0000873static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000874#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000875 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000876#else
877 return true;
878#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000879}
880
junov@chromium.orga907ac32012-02-24 21:54:07 +0000881bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700882 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000883 SkIRect clipBounds;
884 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000885 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000886 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000887
reed96e657d2015-03-10 17:30:07 -0700888 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
889
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000890 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700891 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000892 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000893 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700894 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000895 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000896
reed96e657d2015-03-10 17:30:07 -0700897 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000898 r.roundOut(&ir);
899 // early exit if the layer's bounds are clipped out
900 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000901 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700902 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700903 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000904 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000905 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000906 }
907 } else { // no user bounds, so just use the clip
908 ir = clipBounds;
909 }
reed180aec42015-03-11 10:39:04 -0700910 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000911
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000912 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -0700913 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -0700914 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -0700915 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -0700916 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000917 }
918
919 if (intersection) {
920 *intersection = ir;
921 }
922 return true;
923}
924
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000925int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800926 if (gIgnoreSaveLayerBounds) {
927 bounds = NULL;
928 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000929 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -0700930 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700931 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800932 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000933}
934
reed2ff1fce2014-12-11 07:07:37 -0800935int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800936 if (gIgnoreSaveLayerBounds) {
937 bounds = NULL;
938 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000939 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -0700940 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700941 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800942 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000943}
944
reed2ff1fce2014-12-11 07:07:37 -0800945void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -0700946 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000947#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000948 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000949#endif
950
junov@chromium.orga907ac32012-02-24 21:54:07 +0000951 // do this before we create the layer. We don't call the public save() since
952 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -0800953 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000954
955 fDeviceCMDirty = true;
956
957 SkIRect ir;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000958 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -0800959 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960 }
961
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000962 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
963 // the clipRectBounds() call above?
964 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -0800965 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000966 }
967
reed76033be2015-03-14 10:54:31 -0700968 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -0700969 SkPixelGeometry geo = fProps.pixelGeometry();
970 if (paint) {
reed76033be2015-03-14 10:54:31 -0700971 // TODO: perhaps add a query to filters so we might preserve opaqueness...
972 if (paint->getImageFilter() || paint->getColorFilter()) {
973 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -0700974 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +0000975 }
976 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000977 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
978 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979
reedb2db8982014-11-13 12:41:02 -0800980 SkBaseDevice* device = this->getTopDevice();
981 if (NULL == device) {
982 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800983 return;
reed@google.com76dd2772012-01-05 21:15:07 +0000984 }
reedb2db8982014-11-13 12:41:02 -0800985
reed76033be2015-03-14 10:54:31 -0700986 SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed8dc0ccb2015-03-20 06:32:52 -0700987 device = device->onCreateDevice(SkBaseDevice::CreateInfo(info, usage, geo), paint);
bungeman@google.come25c6842011-08-17 14:53:54 +0000988 if (NULL == device) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800989 SkErrorInternals::SetError( kInternalError_SkError,
990 "Unable to create device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800991 return;
bungeman@google.come25c6842011-08-17 14:53:54 +0000992 }
bsalomon@google.come97f0852011-06-17 13:10:25 +0000993
reed@google.com6f8f2922011-03-04 22:27:10 +0000994 device->setOrigin(ir.fLeft, ir.fTop);
reed96e657d2015-03-10 17:30:07 -0700995 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000996 device->unref();
997
998 layer->fNext = fMCRec->fTopLayer;
999 fMCRec->fLayer = layer;
1000 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001001}
1002
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001003int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1004 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1005}
1006
reed@android.com8a1c16f2008-12-17 15:59:43 +00001007int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1008 SaveFlags flags) {
1009 if (0xFF == alpha) {
1010 return this->saveLayer(bounds, NULL, flags);
1011 } else {
1012 SkPaint tmpPaint;
1013 tmpPaint.setAlpha(alpha);
1014 return this->saveLayer(bounds, &tmpPaint, flags);
1015 }
1016}
1017
reed@android.com8a1c16f2008-12-17 15:59:43 +00001018void SkCanvas::internalRestore() {
1019 SkASSERT(fMCStack.count() != 0);
1020
1021 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001022 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023
reed687fa1c2015-04-07 08:00:56 -07001024 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001025
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001026 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001027 DeviceCM* layer = fMCRec->fLayer; // may be null
1028 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1029 fMCRec->fLayer = NULL;
1030
1031 // now do the normal restore()
1032 fMCRec->~MCRec(); // balanced in save()
1033 fMCStack.pop_back();
1034 fMCRec = (MCRec*)fMCStack.back();
1035
1036 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1037 since if we're being recorded, we don't want to record this (the
1038 recorder will have already recorded the restore).
1039 */
bsalomon49f085d2014-09-05 13:34:00 -07001040 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001041 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001042 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001043 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1044 layer->fPaint);
1045 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001046 fDeviceCMDirty = true;
reedb679ca82015-04-07 04:40:48 -07001047 SkDELETE(layer);
1048 } else {
1049 // we're at the root
1050 SkASSERT(layer == (void*)fBaseLayerStorage);
1051 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001052 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001053 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054}
1055
reed4a8126e2014-09-22 07:29:03 -07001056SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1057 if (NULL == props) {
1058 props = &fProps;
1059 }
1060 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001061}
1062
reed4a8126e2014-09-22 07:29:03 -07001063SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001064 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001065 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001066}
1067
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001068SkImageInfo SkCanvas::imageInfo() const {
1069 SkBaseDevice* dev = this->getDevice();
1070 if (dev) {
1071 return dev->imageInfo();
1072 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001073 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001074 }
1075}
1076
1077const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1078 return this->onPeekPixels(info, rowBytes);
1079}
1080
1081const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1082 SkBaseDevice* dev = this->getDevice();
1083 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1084}
1085
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001086void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1087 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1088 if (pixels && origin) {
1089 *origin = this->getTopDevice(false)->getOrigin();
1090 }
1091 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001092}
1093
1094void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1095 SkBaseDevice* dev = this->getTopDevice();
1096 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1097}
1098
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001099SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1100 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1101 if (NULL == fAddr) {
1102 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001103 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001104 return; // failure, fAddr is NULL
1105 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001106 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1107 return; // failure, fAddr is NULL
1108 }
1109 fAddr = fBitmap.getPixels();
1110 fRowBytes = fBitmap.rowBytes();
1111 }
1112 SkASSERT(fAddr); // success
1113}
1114
1115bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1116 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001117 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001118 } else {
1119 bitmap->reset();
1120 return false;
1121 }
1122}
1123
reed@android.com8a1c16f2008-12-17 15:59:43 +00001124/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001125void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001126 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001127 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001128 return;
1129 }
1130
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001131 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001132 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001133 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001134 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001135
1136 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001137
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001138 SkRect storage;
1139 const SkRect* bounds = NULL;
1140 if (paint && paint->canComputeFastBounds()) {
1141 bitmap.getBounds(&storage);
1142 matrix.mapRect(&storage);
1143 bounds = &paint->computeFastBounds(storage, &storage);
1144 }
1145
1146 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001147
1148 while (iter.next()) {
1149 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1150 }
1151
1152 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001153}
1154
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001155void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed@google.com8926b162012-03-23 15:36:36 +00001156 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001157 SkPaint tmp;
1158 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001159 paint = &tmp;
1160 }
reed@google.com4b226022011-01-11 18:32:13 +00001161
reed@google.com8926b162012-03-23 15:36:36 +00001162 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001163 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001164 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001165 paint = &looper.paint();
1166 SkImageFilter* filter = paint->getImageFilter();
1167 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001168 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001169 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001170 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001171 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001172 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001173 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001174 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001175 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001176 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001177 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001178 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001179 SkPaint tmpUnfiltered(*paint);
1180 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001181 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1182 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001183 }
1184 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001185 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001186 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001187 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001188 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001189}
1190
reed41af9662015-01-05 07:49:08 -08001191void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001192 if (gTreatSpriteAsBitmap) {
1193 this->save();
1194 this->resetMatrix();
1195 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1196 this->restore();
1197 return;
1198 }
1199
danakj9881d632014-11-26 12:41:06 -08001200 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001201 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001202 return;
1203 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001204 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001205
reed@google.com8926b162012-03-23 15:36:36 +00001206 SkPaint tmp;
1207 if (NULL == paint) {
1208 paint = &tmp;
1209 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001210
reed@google.com8926b162012-03-23 15:36:36 +00001211 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001212
reed@google.com8926b162012-03-23 15:36:36 +00001213 while (iter.next()) {
1214 paint = &looper.paint();
1215 SkImageFilter* filter = paint->getImageFilter();
1216 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1217 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001218 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001219 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001220 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001221 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001222 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001223 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001224 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001225 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001226 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001227 SkPaint tmpUnfiltered(*paint);
1228 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001229 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001230 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001231 }
1232 } else {
1233 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1234 }
1235 }
1236 LOOPER_END
1237}
1238
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001240void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001241 SkMatrix m;
1242 m.setTranslate(dx, dy);
1243 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244}
1245
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001246void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001247 SkMatrix m;
1248 m.setScale(sx, sy);
1249 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001250}
1251
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001252void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001253 SkMatrix m;
1254 m.setRotate(degrees);
1255 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001256}
1257
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001258void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001259 SkMatrix m;
1260 m.setSkew(sx, sy);
1261 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001262}
1263
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001264void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001265 if (matrix.isIdentity()) {
1266 return;
1267 }
1268
reed2ff1fce2014-12-11 07:07:37 -08001269 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001270 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001271 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001272 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001273
1274 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001275}
1276
reed@android.com8a1c16f2008-12-17 15:59:43 +00001277void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001278 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001279 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001280 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001281 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001282 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283}
1284
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285void SkCanvas::resetMatrix() {
1286 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001287
reed@android.com8a1c16f2008-12-17 15:59:43 +00001288 matrix.reset();
1289 this->setMatrix(matrix);
1290}
1291
1292//////////////////////////////////////////////////////////////////////////////
1293
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001294void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001295 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001296 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1297 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001298}
1299
1300void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001301#ifdef SK_ENABLE_CLIP_QUICKREJECT
1302 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001303 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001304 return false;
1305 }
1306
reed@google.com3b3e8952012-08-16 20:53:31 +00001307 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001308 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001309 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001310
reed687fa1c2015-04-07 08:00:56 -07001311 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001312 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001313 }
1314 }
1315#endif
1316
reed@google.com5c3d1472011-02-22 19:12:23 +00001317 AutoValidateClip avc(this);
1318
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001320 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001321 if (!fAllowSoftClip) {
1322 edgeStyle = kHard_ClipEdgeStyle;
1323 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001324
reed1f836ee2014-07-07 07:49:34 -07001325 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001326 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001327 // the matrix. This means we don't have to a) make a path, and b) tell
1328 // the region code to scan-convert the path, only to discover that it
1329 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001330 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001331
reed1f836ee2014-07-07 07:49:34 -07001332 fMCRec->fMatrix.mapRect(&r, rect);
reed687fa1c2015-04-07 08:00:56 -07001333 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001334 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001336 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001337 // and clip against that, since it can handle any matrix. However, to
1338 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1339 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340 SkPath path;
1341
1342 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001343 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344 }
1345}
1346
reed73e714e2014-09-04 09:02:23 -07001347static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1348 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001349 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001350}
1351
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001352void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001353 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001354 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001355 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001356 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1357 } else {
1358 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001359 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001360}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001361
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001362void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001363 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001364 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001365 AutoValidateClip avc(this);
1366
1367 fDeviceCMDirty = true;
1368 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001369 if (!fAllowSoftClip) {
1370 edgeStyle = kHard_ClipEdgeStyle;
1371 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001372
reed687fa1c2015-04-07 08:00:56 -07001373 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001374
1375 SkPath devPath;
1376 devPath.addRRect(transformedRRect);
1377
reed73e714e2014-09-04 09:02:23 -07001378 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001379 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001380 }
1381
1382 SkPath path;
1383 path.addRRect(rrect);
1384 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001385 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001386}
1387
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001388void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001389 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001390 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1391 SkRect r;
1392 if (!path.isInverseFillType() && path.isRect(&r)) {
1393 this->onClipRect(r, op, edgeStyle);
1394 } else {
1395 this->onClipPath(path, op, edgeStyle);
1396 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001397}
1398
1399void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001400#ifdef SK_ENABLE_CLIP_QUICKREJECT
1401 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001402 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001403 return false;
1404 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001405
reed@google.com3b3e8952012-08-16 20:53:31 +00001406 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001407 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001408 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001409
reed687fa1c2015-04-07 08:00:56 -07001410 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001411 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001412 }
1413 }
1414#endif
1415
reed@google.com5c3d1472011-02-22 19:12:23 +00001416 AutoValidateClip avc(this);
1417
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001419 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001420 if (!fAllowSoftClip) {
1421 edgeStyle = kHard_ClipEdgeStyle;
1422 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423
1424 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001425 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001426
reed@google.comfe701122011-11-08 19:41:23 +00001427 // Check if the transfomation, or the original path itself
1428 // made us empty. Note this can also happen if we contained NaN
1429 // values. computing the bounds detects this, and will set our
1430 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1431 if (devPath.getBounds().isEmpty()) {
1432 // resetting the path will remove any NaN or other wanky values
1433 // that might upset our scan converter.
1434 devPath.reset();
1435 }
1436
reed@google.com5c3d1472011-02-22 19:12:23 +00001437 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001438 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001439
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001440 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001441 bool clipIsAA = getClipStack()->asPath(&devPath);
1442 if (clipIsAA) {
1443 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001444 }
fmalita1a481fe2015-02-04 07:39:34 -08001445
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001446 op = SkRegion::kReplace_Op;
1447 }
1448
reed73e714e2014-09-04 09:02:23 -07001449 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450}
1451
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001452void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001453 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001454 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001455}
1456
1457void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001458 AutoValidateClip avc(this);
1459
reed@android.com8a1c16f2008-12-17 15:59:43 +00001460 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001461 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001462
reed@google.com5c3d1472011-02-22 19:12:23 +00001463 // todo: signal fClipStack that we have a region, and therefore (I guess)
1464 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001465 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001466
reed1f836ee2014-07-07 07:49:34 -07001467 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001468}
1469
reed@google.com819c9212011-02-23 18:56:55 +00001470#ifdef SK_DEBUG
1471void SkCanvas::validateClip() const {
1472 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001473 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001474 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001475 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001476 return;
1477 }
1478
reed@google.com819c9212011-02-23 18:56:55 +00001479 SkIRect ir;
1480 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001481 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001482
reed687fa1c2015-04-07 08:00:56 -07001483 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001484 const SkClipStack::Element* element;
1485 while ((element = iter.next()) != NULL) {
1486 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001487 case SkClipStack::Element::kRect_Type:
1488 element->getRect().round(&ir);
1489 tmpClip.op(ir, element->getOp());
1490 break;
1491 case SkClipStack::Element::kEmpty_Type:
1492 tmpClip.setEmpty();
1493 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001494 default: {
1495 SkPath path;
1496 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001497 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001498 break;
1499 }
reed@google.com819c9212011-02-23 18:56:55 +00001500 }
1501 }
reed@google.com819c9212011-02-23 18:56:55 +00001502}
1503#endif
1504
reed@google.com90c07ea2012-04-13 13:50:27 +00001505void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001506 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001507 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001508
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001509 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001510 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001511 }
1512}
1513
reed@google.com5c3d1472011-02-22 19:12:23 +00001514///////////////////////////////////////////////////////////////////////////////
1515
reed@google.com754de5f2014-02-24 19:38:20 +00001516bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001517 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001518}
1519
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001520bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001521 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001522}
1523
reed@google.com3b3e8952012-08-16 20:53:31 +00001524bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001525 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001526 return true;
1527
reed1f836ee2014-07-07 07:49:34 -07001528 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001529 return true;
1530 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001531
reed1f836ee2014-07-07 07:49:34 -07001532 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001533 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001534 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001535 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001536 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001537 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001538
reed@android.coma380ae42009-07-21 01:17:02 +00001539 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001540 // TODO: should we use | instead, or compare all 4 at once?
1541 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001542 return true;
1543 }
reed@google.comc0784db2013-12-13 21:16:12 +00001544 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001545 return true;
1546 }
1547 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001548 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001549}
1550
reed@google.com3b3e8952012-08-16 20:53:31 +00001551bool SkCanvas::quickReject(const SkPath& path) const {
1552 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001553}
1554
reed@google.com3b3e8952012-08-16 20:53:31 +00001555bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001556 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001557 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001558 return false;
1559 }
1560
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001561 SkMatrix inverse;
1562 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001563 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001564 if (bounds) {
1565 bounds->setEmpty();
1566 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001567 return false;
1568 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001569
bsalomon49f085d2014-09-05 13:34:00 -07001570 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001571 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001572 // adjust it outwards in case we are antialiasing
1573 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001574
reed@google.com8f4d2302013-12-17 16:44:46 +00001575 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1576 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001577 inverse.mapRect(bounds, r);
1578 }
1579 return true;
1580}
1581
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001582bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001583 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001584 if (clip.isEmpty()) {
1585 if (bounds) {
1586 bounds->setEmpty();
1587 }
1588 return false;
1589 }
1590
bsalomon49f085d2014-09-05 13:34:00 -07001591 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001592 *bounds = clip.getBounds();
1593 }
1594 return true;
1595}
1596
reed@android.com8a1c16f2008-12-17 15:59:43 +00001597const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001598 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001599}
1600
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001601const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001602 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001603}
1604
reed@google.com9c135db2014-03-12 18:28:35 +00001605GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1606 SkBaseDevice* dev = this->getTopDevice();
1607 return dev ? dev->accessRenderTarget() : NULL;
1608}
1609
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001610GrContext* SkCanvas::getGrContext() {
1611#if SK_SUPPORT_GPU
1612 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001613 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001614 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001615 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001616 return renderTarget->getContext();
1617 }
1618 }
1619#endif
1620
1621 return NULL;
1622
1623}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001624
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001625void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1626 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001627 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001628 if (outer.isEmpty()) {
1629 return;
1630 }
1631 if (inner.isEmpty()) {
1632 this->drawRRect(outer, paint);
1633 return;
1634 }
1635
1636 // We don't have this method (yet), but technically this is what we should
1637 // be able to assert...
1638 // SkASSERT(outer.contains(inner));
1639 //
1640 // For now at least check for containment of bounds
1641 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1642
1643 this->onDrawDRRect(outer, inner, paint);
1644}
1645
reed41af9662015-01-05 07:49:08 -08001646// These need to stop being virtual -- clients need to override the onDraw... versions
1647
1648void SkCanvas::drawPaint(const SkPaint& paint) {
1649 this->onDrawPaint(paint);
1650}
1651
1652void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1653 this->onDrawRect(r, paint);
1654}
1655
1656void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1657 this->onDrawOval(r, paint);
1658}
1659
1660void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1661 this->onDrawRRect(rrect, paint);
1662}
1663
1664void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1665 this->onDrawPoints(mode, count, pts, paint);
1666}
1667
1668void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1669 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1670 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1671 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1672 indices, indexCount, paint);
1673}
1674
1675void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1676 this->onDrawPath(path, paint);
1677}
1678
1679void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1680 this->onDrawImage(image, dx, dy, paint);
1681}
1682
1683void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1684 const SkPaint* paint) {
1685 this->onDrawImageRect(image, src, dst, paint);
1686}
1687
1688void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001689 if (bitmap.empty()) {
1690 return;
1691 }
reed41af9662015-01-05 07:49:08 -08001692 this->onDrawBitmap(bitmap, dx, dy, paint);
1693}
1694
1695void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1696 const SkPaint* paint, DrawBitmapRectFlags flags) {
tomhudson2df6fd62015-04-09 09:20:19 -07001697 if (bitmap.empty()) {
1698 return;
1699 }
reed41af9662015-01-05 07:49:08 -08001700 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1701}
1702
1703void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1704 const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001705 if (bitmap.empty()) {
1706 return;
1707 }
reed41af9662015-01-05 07:49:08 -08001708 this->onDrawBitmapNine(bitmap, center, dst, paint);
1709}
1710
1711void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001712 if (bitmap.empty()) {
1713 return;
1714 }
reed41af9662015-01-05 07:49:08 -08001715 this->onDrawSprite(bitmap, left, top, paint);
1716}
1717
reed@android.com8a1c16f2008-12-17 15:59:43 +00001718//////////////////////////////////////////////////////////////////////////////
1719// These are the virtual drawing methods
1720//////////////////////////////////////////////////////////////////////////////
1721
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001722void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001723 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001724 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1725 }
1726}
1727
reed41af9662015-01-05 07:49:08 -08001728void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001729 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001730 this->internalDrawPaint(paint);
1731}
1732
1733void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001734 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001735
1736 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001737 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001738 }
1739
reed@google.com4e2b3d32011-04-07 14:18:59 +00001740 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001741}
1742
reed41af9662015-01-05 07:49:08 -08001743void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1744 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001745 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001746 if ((long)count <= 0) {
1747 return;
1748 }
1749
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001750 SkRect r, storage;
1751 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001752 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001753 // special-case 2 points (common for drawing a single line)
1754 if (2 == count) {
1755 r.set(pts[0], pts[1]);
1756 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001757 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001758 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001759 bounds = &paint.computeFastStrokeBounds(r, &storage);
1760 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001761 return;
1762 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001763 }
reed@google.coma584aed2012-05-16 14:06:02 +00001764
reed@android.com8a1c16f2008-12-17 15:59:43 +00001765 SkASSERT(pts != NULL);
1766
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001767 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001768
reed@android.com8a1c16f2008-12-17 15:59:43 +00001769 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001770 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001771 }
reed@google.com4b226022011-01-11 18:32:13 +00001772
reed@google.com4e2b3d32011-04-07 14:18:59 +00001773 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001774}
1775
reed41af9662015-01-05 07:49:08 -08001776void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001777 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001778 SkRect storage;
1779 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001780 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001781 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1782 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1783 SkRect tmp(r);
1784 tmp.sort();
1785
1786 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001787 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001788 return;
1789 }
1790 }
reed@google.com4b226022011-01-11 18:32:13 +00001791
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001792 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001793
1794 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001795 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001796 }
1797
reed@google.com4e2b3d32011-04-07 14:18:59 +00001798 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001799}
1800
reed41af9662015-01-05 07:49:08 -08001801void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001802 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001803 SkRect storage;
1804 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001805 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001806 bounds = &paint.computeFastBounds(oval, &storage);
1807 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001808 return;
1809 }
1810 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001811
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001812 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001813
1814 while (iter.next()) {
1815 iter.fDevice->drawOval(iter, oval, looper.paint());
1816 }
1817
1818 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001819}
1820
reed41af9662015-01-05 07:49:08 -08001821void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001822 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001823 SkRect storage;
1824 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001825 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001826 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1827 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001828 return;
1829 }
1830 }
1831
1832 if (rrect.isRect()) {
1833 // call the non-virtual version
1834 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001835 return;
1836 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001837 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001838 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1839 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001840 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001841
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001842 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001843
1844 while (iter.next()) {
1845 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1846 }
1847
1848 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001849}
1850
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001851void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1852 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001853 SkRect storage;
1854 const SkRect* bounds = NULL;
1855 if (paint.canComputeFastBounds()) {
1856 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1857 if (this->quickReject(*bounds)) {
1858 return;
1859 }
1860 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001861
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001862 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001863
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001864 while (iter.next()) {
1865 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1866 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001867
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001868 LOOPER_END
1869}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001870
reed41af9662015-01-05 07:49:08 -08001871void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001872 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001873 if (!path.isFinite()) {
1874 return;
1875 }
1876
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001877 SkRect storage;
1878 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001879 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001880 const SkRect& pathBounds = path.getBounds();
1881 bounds = &paint.computeFastBounds(pathBounds, &storage);
1882 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001883 return;
1884 }
1885 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001886
1887 const SkRect& r = path.getBounds();
1888 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001889 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001890 this->internalDrawPaint(paint);
1891 }
1892 return;
1893 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001894
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001895 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001896
1897 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001898 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001899 }
1900
reed@google.com4e2b3d32011-04-07 14:18:59 +00001901 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001902}
1903
kkinnunena9baa652015-03-05 06:33:54 -08001904void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001905 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
kkinnunena9baa652015-03-05 06:33:54 -08001906 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001907}
1908
reed41af9662015-01-05 07:49:08 -08001909void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1910 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001911 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
kkinnunena9baa652015-03-05 06:33:54 -08001912 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001913}
1914
reed41af9662015-01-05 07:49:08 -08001915void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001916 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001917 SkDEBUGCODE(bitmap.validate();)
1918
reed@google.com3d608122011-11-21 15:16:16 +00001919 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001920 SkRect bounds = {
1921 x, y,
1922 x + SkIntToScalar(bitmap.width()),
1923 y + SkIntToScalar(bitmap.height())
1924 };
1925 if (paint) {
1926 (void)paint->computeFastBounds(bounds, &bounds);
1927 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001928 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001929 return;
1930 }
1931 }
reed@google.com4b226022011-01-11 18:32:13 +00001932
reed@android.com8a1c16f2008-12-17 15:59:43 +00001933 SkMatrix matrix;
1934 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001935 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001936}
1937
reed@google.com9987ec32011-09-07 11:57:52 +00001938// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00001939void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001940 const SkRect& dst, const SkPaint* paint,
1941 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001942 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001943 return;
1944 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001945
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001946 SkRect storage;
1947 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00001948 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001949 if (paint) {
1950 bounds = &paint->computeFastBounds(dst, &storage);
1951 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001952 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001953 return;
1954 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001955 }
reed@google.com3d608122011-11-21 15:16:16 +00001956
reed@google.com33535f32012-09-25 15:37:50 +00001957 SkLazyPaint lazy;
1958 if (NULL == paint) {
1959 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001960 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001961
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001962 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001963
reed@google.com33535f32012-09-25 15:37:50 +00001964 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001965 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00001966 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001967
reed@google.com33535f32012-09-25 15:37:50 +00001968 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001969}
1970
reed41af9662015-01-05 07:49:08 -08001971void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1972 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08001973 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00001974 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001975 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00001976}
1977
reed@google.com9987ec32011-09-07 11:57:52 +00001978void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1979 const SkIRect& center, const SkRect& dst,
1980 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001981 if (bitmap.drawsNothing()) {
1982 return;
1983 }
reed@google.com3d608122011-11-21 15:16:16 +00001984 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00001985 SkRect storage;
1986 const SkRect* bounds = &dst;
1987 if (paint) {
1988 bounds = &paint->computeFastBounds(dst, &storage);
1989 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001990 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001991 return;
1992 }
1993 }
1994
reed@google.com9987ec32011-09-07 11:57:52 +00001995 const int32_t w = bitmap.width();
1996 const int32_t h = bitmap.height();
1997
1998 SkIRect c = center;
1999 // pin center to the bounds of the bitmap
2000 c.fLeft = SkMax32(0, center.fLeft);
2001 c.fTop = SkMax32(0, center.fTop);
2002 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2003 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2004
reed@google.com71121732012-09-18 15:14:33 +00002005 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002006 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00002007 };
2008 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002009 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00002010 };
reed@google.com9987ec32011-09-07 11:57:52 +00002011 SkScalar dstX[4] = {
2012 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2013 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2014 };
2015 SkScalar dstY[4] = {
2016 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2017 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2018 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002019
reed@google.com9987ec32011-09-07 11:57:52 +00002020 if (dstX[1] > dstX[2]) {
2021 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2022 dstX[2] = dstX[1];
2023 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002024
reed@google.com9987ec32011-09-07 11:57:52 +00002025 if (dstY[1] > dstY[2]) {
2026 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2027 dstY[2] = dstY[1];
2028 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002029
reed@google.com9987ec32011-09-07 11:57:52 +00002030 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00002031 SkRect s, d;
2032
reed@google.com9987ec32011-09-07 11:57:52 +00002033 s.fTop = srcY[y];
2034 s.fBottom = srcY[y+1];
2035 d.fTop = dstY[y];
2036 d.fBottom = dstY[y+1];
2037 for (int x = 0; x < 3; x++) {
2038 s.fLeft = srcX[x];
2039 s.fRight = srcX[x+1];
2040 d.fLeft = dstX[x];
2041 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002042 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00002043 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00002044 }
2045 }
2046}
2047
reed41af9662015-01-05 07:49:08 -08002048void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2049 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002050 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002051 SkDEBUGCODE(bitmap.validate();)
2052
2053 // Need a device entry-point, so gpu can use a mesh
2054 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2055}
2056
reed@google.comf67e4cf2011-03-15 20:56:58 +00002057class SkDeviceFilteredPaint {
2058public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002059 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002060 uint32_t filteredFlags = device->filterTextFlags(paint);
2061 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002062 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002063 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002064 fPaint = newPaint;
2065 } else {
2066 fPaint = &paint;
2067 }
2068 }
2069
reed@google.comf67e4cf2011-03-15 20:56:58 +00002070 const SkPaint& paint() const { return *fPaint; }
2071
2072private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002073 const SkPaint* fPaint;
2074 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002075};
2076
bungeman@google.com52c748b2011-08-22 21:30:43 +00002077void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2078 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002079 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002080 draw.fDevice->drawRect(draw, r, paint);
2081 } else {
2082 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002083 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002084 draw.fDevice->drawRect(draw, r, p);
2085 }
2086}
2087
2088void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2089 const char text[], size_t byteLength,
2090 SkScalar x, SkScalar y) {
2091 SkASSERT(byteLength == 0 || text != NULL);
2092
2093 // nothing to draw
2094 if (text == NULL || byteLength == 0 ||
2095 draw.fClip->isEmpty() ||
2096 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2097 return;
2098 }
2099
2100 SkScalar width = 0;
2101 SkPoint start;
2102
2103 start.set(0, 0); // to avoid warning
2104 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2105 SkPaint::kStrikeThruText_Flag)) {
2106 width = paint.measureText(text, byteLength);
2107
2108 SkScalar offsetX = 0;
2109 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2110 offsetX = SkScalarHalf(width);
2111 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2112 offsetX = width;
2113 }
2114 start.set(x - offsetX, y);
2115 }
2116
2117 if (0 == width) {
2118 return;
2119 }
2120
2121 uint32_t flags = paint.getFlags();
2122
2123 if (flags & (SkPaint::kUnderlineText_Flag |
2124 SkPaint::kStrikeThruText_Flag)) {
2125 SkScalar textSize = paint.getTextSize();
2126 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2127 SkRect r;
2128
2129 r.fLeft = start.fX;
2130 r.fRight = start.fX + width;
2131
2132 if (flags & SkPaint::kUnderlineText_Flag) {
2133 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2134 start.fY);
2135 r.fTop = offset;
2136 r.fBottom = offset + height;
2137 DrawRect(draw, paint, r, textSize);
2138 }
2139 if (flags & SkPaint::kStrikeThruText_Flag) {
2140 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2141 start.fY);
2142 r.fTop = offset;
2143 r.fBottom = offset + height;
2144 DrawRect(draw, paint, r, textSize);
2145 }
2146 }
2147}
2148
reed@google.come0d9ce82014-04-23 04:00:17 +00002149void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2150 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002151 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002152
2153 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002154 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002155 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002156 DrawTextDecorations(iter, dfp.paint(),
2157 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002158 }
2159
reed@google.com4e2b3d32011-04-07 14:18:59 +00002160 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002161}
2162
reed@google.come0d9ce82014-04-23 04:00:17 +00002163void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2164 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002165 SkPoint textOffset = SkPoint::Make(0, 0);
2166
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()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002170 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002171 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002172 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002173 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002174
reed@google.com4e2b3d32011-04-07 14:18:59 +00002175 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002176}
2177
reed@google.come0d9ce82014-04-23 04:00:17 +00002178void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2179 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002180
2181 SkPoint textOffset = SkPoint::Make(0, constY);
2182
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002183 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002184
reed@android.com8a1c16f2008-12-17 15:59:43 +00002185 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002186 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002187 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002188 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002189 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002190
reed@google.com4e2b3d32011-04-07 14:18:59 +00002191 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002192}
2193
reed@google.come0d9ce82014-04-23 04:00:17 +00002194void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2195 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002196 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002197
reed@android.com8a1c16f2008-12-17 15:59:43 +00002198 while (iter.next()) {
2199 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002200 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002201 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002202
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002203 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002204}
2205
fmalita00d5c2c2014-08-21 08:53:26 -07002206void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2207 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002208
fmalita85d5eb92015-03-04 11:20:12 -08002209 SkRect storage;
2210 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002211 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002212 storage = blob->bounds().makeOffset(x, y);
2213 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002214
fmalita85d5eb92015-03-04 11:20:12 -08002215 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002216 return;
2217 }
2218 }
2219
fmalita024f9962015-03-03 19:08:17 -08002220 // We cannot filter in the looper as we normally do, because the paint is
2221 // incomplete at this point (text-related attributes are embedded within blob run paints).
2222 SkDrawFilter* drawFilter = fMCRec->fFilter;
2223 fMCRec->fFilter = NULL;
2224
fmalita85d5eb92015-03-04 11:20:12 -08002225 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002226
fmalitaaa1b9122014-08-28 14:32:24 -07002227 while (iter.next()) {
2228 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002229 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002230 }
2231
fmalitaaa1b9122014-08-28 14:32:24 -07002232 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002233
2234 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002235}
2236
reed@google.come0d9ce82014-04-23 04:00:17 +00002237// These will become non-virtual, so they always call the (virtual) onDraw... method
2238void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2239 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002240 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002241 this->onDrawText(text, byteLength, x, y, paint);
2242}
2243void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2244 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002245 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002246 this->onDrawPosText(text, byteLength, pos, paint);
2247}
2248void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2249 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002250 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002251 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2252}
2253void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2254 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002255 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002256 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2257}
fmalita00d5c2c2014-08-21 08:53:26 -07002258void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2259 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002260 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002261 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002262 this->onDrawTextBlob(blob, x, y, paint);
2263 }
2264}
reed@google.come0d9ce82014-04-23 04:00:17 +00002265
reed41af9662015-01-05 07:49:08 -08002266void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2267 const SkPoint verts[], const SkPoint texs[],
2268 const SkColor colors[], SkXfermode* xmode,
2269 const uint16_t indices[], int indexCount,
2270 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002271 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002272 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002273
reed@android.com8a1c16f2008-12-17 15:59:43 +00002274 while (iter.next()) {
2275 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002276 colors, xmode, indices, indexCount,
2277 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002278 }
reed@google.com4b226022011-01-11 18:32:13 +00002279
reed@google.com4e2b3d32011-04-07 14:18:59 +00002280 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002281}
2282
dandovb3c9d1c2014-08-12 08:34:29 -07002283void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2284 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002285 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002286 if (NULL == cubics) {
2287 return;
2288 }
mtklein6cfa73a2014-08-13 13:33:49 -07002289
dandovecfff212014-08-04 10:02:00 -07002290 // Since a patch is always within the convex hull of the control points, we discard it when its
2291 // bounding rectangle is completely outside the current clip.
2292 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002293 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002294 if (this->quickReject(bounds)) {
2295 return;
2296 }
mtklein6cfa73a2014-08-13 13:33:49 -07002297
dandovb3c9d1c2014-08-12 08:34:29 -07002298 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2299}
2300
2301void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2302 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2303
dandovecfff212014-08-04 10:02:00 -07002304 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002305
dandovecfff212014-08-04 10:02:00 -07002306 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002307 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002308 }
mtklein6cfa73a2014-08-13 13:33:49 -07002309
dandovecfff212014-08-04 10:02:00 -07002310 LOOPER_END
2311}
2312
reed3cb38402015-02-06 08:36:15 -08002313void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002314 if (dr && !this->quickReject(dr->getBounds())) {
2315 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002316 }
2317}
2318
reed3cb38402015-02-06 08:36:15 -08002319void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002320 dr->draw(this);
2321}
2322
reed@android.com8a1c16f2008-12-17 15:59:43 +00002323//////////////////////////////////////////////////////////////////////////////
2324// These methods are NOT virtual, and therefore must call back into virtual
2325// methods, rather than actually drawing themselves.
2326//////////////////////////////////////////////////////////////////////////////
2327
2328void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002329 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002330 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002331 SkPaint paint;
2332
2333 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002334 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002335 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002336 }
2337 this->drawPaint(paint);
2338}
2339
reed@android.com845fdac2009-06-23 03:01:32 +00002340void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002341 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002342 SkPaint paint;
2343
2344 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002345 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002346 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002347 }
2348 this->drawPaint(paint);
2349}
2350
2351void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002352 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002353 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002354
reed@android.com8a1c16f2008-12-17 15:59:43 +00002355 pt.set(x, y);
2356 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2357}
2358
2359void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002360 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002361 SkPoint pt;
2362 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002363
reed@android.com8a1c16f2008-12-17 15:59:43 +00002364 pt.set(x, y);
2365 paint.setColor(color);
2366 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2367}
2368
2369void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2370 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002371 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002372 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002373
reed@android.com8a1c16f2008-12-17 15:59:43 +00002374 pts[0].set(x0, y0);
2375 pts[1].set(x1, y1);
2376 this->drawPoints(kLines_PointMode, 2, pts, paint);
2377}
2378
2379void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2380 SkScalar right, SkScalar bottom,
2381 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002382 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002383 SkRect r;
2384
2385 r.set(left, top, right, bottom);
2386 this->drawRect(r, paint);
2387}
2388
2389void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2390 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002391 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002392 if (radius < 0) {
2393 radius = 0;
2394 }
2395
2396 SkRect r;
2397 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002398 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002399}
2400
2401void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2402 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002403 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002404 if (rx > 0 && ry > 0) {
2405 if (paint.canComputeFastBounds()) {
2406 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002407 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002408 return;
2409 }
2410 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002411 SkRRect rrect;
2412 rrect.setRectXY(r, rx, ry);
2413 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002414 } else {
2415 this->drawRect(r, paint);
2416 }
2417}
2418
reed@android.com8a1c16f2008-12-17 15:59:43 +00002419void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2420 SkScalar sweepAngle, bool useCenter,
2421 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002422 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002423 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2424 this->drawOval(oval, paint);
2425 } else {
2426 SkPath path;
2427 if (useCenter) {
2428 path.moveTo(oval.centerX(), oval.centerY());
2429 }
2430 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2431 if (useCenter) {
2432 path.close();
2433 }
2434 this->drawPath(path, paint);
2435 }
2436}
2437
2438void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2439 const SkPath& path, SkScalar hOffset,
2440 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002441 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002442 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002443
reed@android.com8a1c16f2008-12-17 15:59:43 +00002444 matrix.setTranslate(hOffset, vOffset);
2445 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2446}
2447
reed@android.comf76bacf2009-05-13 14:00:33 +00002448///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002449void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002450 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002451 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002452 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002453 }
2454}
2455
reedd5fa1a42014-08-09 11:08:05 -07002456void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002457 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002458 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002459 if (matrix && matrix->isIdentity()) {
2460 matrix = NULL;
2461 }
2462 this->onDrawPicture(picture, matrix, paint);
2463 }
2464}
robertphillips9b14f262014-06-04 05:40:44 -07002465
reedd5fa1a42014-08-09 11:08:05 -07002466void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2467 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002468 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002469 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002470 // Canvas has to first give the device the opportunity to render
2471 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002472 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002473 return; // the device has rendered the entire picture
2474 }
2475 }
2476
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002477 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002478
robertphillipsc5ba71d2014-09-04 08:42:50 -07002479 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002480}
2481
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482///////////////////////////////////////////////////////////////////////////////
2483///////////////////////////////////////////////////////////////////////////////
2484
2485SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002486 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002487
2488 SkASSERT(canvas);
2489
2490 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2491 fDone = !fImpl->next();
2492}
2493
2494SkCanvas::LayerIter::~LayerIter() {
2495 fImpl->~SkDrawIter();
2496}
2497
2498void SkCanvas::LayerIter::next() {
2499 fDone = !fImpl->next();
2500}
2501
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002502SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002503 return fImpl->getDevice();
2504}
2505
2506const SkMatrix& SkCanvas::LayerIter::matrix() const {
2507 return fImpl->getMatrix();
2508}
2509
2510const SkPaint& SkCanvas::LayerIter::paint() const {
2511 const SkPaint* paint = fImpl->getPaint();
2512 if (NULL == paint) {
2513 paint = &fDefaultPaint;
2514 }
2515 return *paint;
2516}
2517
2518const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2519int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2520int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002521
2522///////////////////////////////////////////////////////////////////////////////
2523
fmalitac3b589a2014-06-05 12:40:07 -07002524SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002525
2526///////////////////////////////////////////////////////////////////////////////
2527
2528static bool supported_for_raster_canvas(const SkImageInfo& info) {
2529 switch (info.alphaType()) {
2530 case kPremul_SkAlphaType:
2531 case kOpaque_SkAlphaType:
2532 break;
2533 default:
2534 return false;
2535 }
2536
2537 switch (info.colorType()) {
2538 case kAlpha_8_SkColorType:
2539 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002540 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002541 break;
2542 default:
2543 return false;
2544 }
2545
2546 return true;
2547}
2548
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002549SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2550 if (!supported_for_raster_canvas(info)) {
2551 return NULL;
2552 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002553
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002554 SkBitmap bitmap;
2555 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2556 return NULL;
2557 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002558 return SkNEW_ARGS(SkCanvas, (bitmap));
2559}
reedd5fa1a42014-08-09 11:08:05 -07002560
2561///////////////////////////////////////////////////////////////////////////////
2562
2563SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002564 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002565 : fCanvas(canvas)
2566 , fSaveCount(canvas->getSaveCount())
2567{
bsalomon49f085d2014-09-05 13:34:00 -07002568 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002569 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002570 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002571 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002572 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002573 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002574 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002575 canvas->save();
2576 }
mtklein6cfa73a2014-08-13 13:33:49 -07002577
bsalomon49f085d2014-09-05 13:34:00 -07002578 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002579 canvas->concat(*matrix);
2580 }
2581}
2582
2583SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2584 fCanvas->restoreToCount(fSaveCount);
2585}