blob: 514a45460c23c82c35073686cfd15a522a188514 [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) {
reed2ff1fce2014-12-11 07:07:37 -0800804 this->doSave();
805 }
806}
807
reedf0090cb2014-11-26 08:55:51 -0800808int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800809#ifdef SK_DEBUG
810 int count = 0;
811 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
812 for (;;) {
813 const MCRec* rec = (const MCRec*)iter.next();
814 if (!rec) {
815 break;
816 }
817 count += 1 + rec->fDeferredSaveCount;
818 }
819 SkASSERT(count == fSaveCount);
820#endif
821 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800822}
823
824int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800825 fSaveCount += 1;
826 fMCRec->fDeferredSaveCount += 1;
827 return this->getSaveCount() - 1; // return our prev value
828}
829
830void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800831 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700832
833 SkASSERT(fMCRec->fDeferredSaveCount > 0);
834 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800835 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800836}
837
838void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800839 if (fMCRec->fDeferredSaveCount > 0) {
840 SkASSERT(fSaveCount > 1);
841 fSaveCount -= 1;
842 fMCRec->fDeferredSaveCount -= 1;
843 } else {
844 // check for underflow
845 if (fMCStack.count() > 1) {
846 this->willRestore();
847 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700848 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800849 this->internalRestore();
850 this->didRestore();
851 }
reedf0090cb2014-11-26 08:55:51 -0800852 }
853}
854
855void SkCanvas::restoreToCount(int count) {
856 // sanity check
857 if (count < 1) {
858 count = 1;
859 }
mtkleinf0f14112014-12-12 08:46:25 -0800860
reedf0090cb2014-11-26 08:55:51 -0800861 int n = this->getSaveCount() - count;
862 for (int i = 0; i < n; ++i) {
863 this->restore();
864 }
865}
866
reed2ff1fce2014-12-11 07:07:37 -0800867void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000868 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700869 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000870 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000871
reed687fa1c2015-04-07 08:00:56 -0700872 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000873}
874
reed@android.com8a1c16f2008-12-17 15:59:43 +0000875static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000876#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000877 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000878#else
879 return true;
880#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000881}
882
junov@chromium.orga907ac32012-02-24 21:54:07 +0000883bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700884 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000885 SkIRect clipBounds;
886 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000887 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000888 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000889
reed96e657d2015-03-10 17:30:07 -0700890 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
891
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000892 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700893 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000894 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000895 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700896 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000897 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000898
reed96e657d2015-03-10 17:30:07 -0700899 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000900 r.roundOut(&ir);
901 // early exit if the layer's bounds are clipped out
902 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000903 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700904 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700905 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000906 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000907 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000908 }
909 } else { // no user bounds, so just use the clip
910 ir = clipBounds;
911 }
reed180aec42015-03-11 10:39:04 -0700912 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000913
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000914 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -0700915 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -0700916 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -0700917 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -0700918 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000919 }
920
921 if (intersection) {
922 *intersection = ir;
923 }
924 return true;
925}
926
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000927int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800928 if (gIgnoreSaveLayerBounds) {
929 bounds = NULL;
930 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000931 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -0700932 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700933 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800934 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000935}
936
reed2ff1fce2014-12-11 07:07:37 -0800937int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800938 if (gIgnoreSaveLayerBounds) {
939 bounds = NULL;
940 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000941 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -0700942 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700943 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800944 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000945}
946
reed2ff1fce2014-12-11 07:07:37 -0800947void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -0700948 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000949#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000950 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000951#endif
952
junov@chromium.orga907ac32012-02-24 21:54:07 +0000953 // do this before we create the layer. We don't call the public save() since
954 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -0800955 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000956
957 fDeviceCMDirty = true;
958
959 SkIRect ir;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000960 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -0800961 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962 }
963
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000964 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
965 // the clipRectBounds() call above?
966 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -0800967 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000968 }
969
reed76033be2015-03-14 10:54:31 -0700970 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -0700971 SkPixelGeometry geo = fProps.pixelGeometry();
972 if (paint) {
reed76033be2015-03-14 10:54:31 -0700973 // TODO: perhaps add a query to filters so we might preserve opaqueness...
974 if (paint->getImageFilter() || paint->getColorFilter()) {
975 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -0700976 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +0000977 }
978 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000979 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
980 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000981
reedb2db8982014-11-13 12:41:02 -0800982 SkBaseDevice* device = this->getTopDevice();
983 if (NULL == device) {
984 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800985 return;
reed@google.com76dd2772012-01-05 21:15:07 +0000986 }
reedb2db8982014-11-13 12:41:02 -0800987
reed76033be2015-03-14 10:54:31 -0700988 SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed8dc0ccb2015-03-20 06:32:52 -0700989 device = device->onCreateDevice(SkBaseDevice::CreateInfo(info, usage, geo), paint);
bungeman@google.come25c6842011-08-17 14:53:54 +0000990 if (NULL == device) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800991 SkErrorInternals::SetError( kInternalError_SkError,
992 "Unable to create device for layer.");
reed2ff1fce2014-12-11 07:07:37 -0800993 return;
bungeman@google.come25c6842011-08-17 14:53:54 +0000994 }
bsalomon@google.come97f0852011-06-17 13:10:25 +0000995
reed@google.com6f8f2922011-03-04 22:27:10 +0000996 device->setOrigin(ir.fLeft, ir.fTop);
reed96e657d2015-03-10 17:30:07 -0700997 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000998 device->unref();
999
1000 layer->fNext = fMCRec->fTopLayer;
1001 fMCRec->fLayer = layer;
1002 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001003}
1004
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001005int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1006 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1007}
1008
reed@android.com8a1c16f2008-12-17 15:59:43 +00001009int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1010 SaveFlags flags) {
1011 if (0xFF == alpha) {
1012 return this->saveLayer(bounds, NULL, flags);
1013 } else {
1014 SkPaint tmpPaint;
1015 tmpPaint.setAlpha(alpha);
1016 return this->saveLayer(bounds, &tmpPaint, flags);
1017 }
1018}
1019
reed@android.com8a1c16f2008-12-17 15:59:43 +00001020void SkCanvas::internalRestore() {
1021 SkASSERT(fMCStack.count() != 0);
1022
1023 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001024 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001025
reed687fa1c2015-04-07 08:00:56 -07001026 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001027
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001028 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029 DeviceCM* layer = fMCRec->fLayer; // may be null
1030 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1031 fMCRec->fLayer = NULL;
1032
1033 // now do the normal restore()
1034 fMCRec->~MCRec(); // balanced in save()
1035 fMCStack.pop_back();
1036 fMCRec = (MCRec*)fMCStack.back();
1037
1038 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1039 since if we're being recorded, we don't want to record this (the
1040 recorder will have already recorded the restore).
1041 */
bsalomon49f085d2014-09-05 13:34:00 -07001042 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001043 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001044 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001045 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1046 layer->fPaint);
1047 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001048 fDeviceCMDirty = true;
reedb679ca82015-04-07 04:40:48 -07001049 SkDELETE(layer);
1050 } else {
1051 // we're at the root
1052 SkASSERT(layer == (void*)fBaseLayerStorage);
1053 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001055 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056}
1057
reed4a8126e2014-09-22 07:29:03 -07001058SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1059 if (NULL == props) {
1060 props = &fProps;
1061 }
1062 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001063}
1064
reed4a8126e2014-09-22 07:29:03 -07001065SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001066 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001067 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001068}
1069
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001070SkImageInfo SkCanvas::imageInfo() const {
1071 SkBaseDevice* dev = this->getDevice();
1072 if (dev) {
1073 return dev->imageInfo();
1074 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001075 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001076 }
1077}
1078
1079const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1080 return this->onPeekPixels(info, rowBytes);
1081}
1082
1083const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1084 SkBaseDevice* dev = this->getDevice();
1085 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1086}
1087
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001088void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1089 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1090 if (pixels && origin) {
1091 *origin = this->getTopDevice(false)->getOrigin();
1092 }
1093 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001094}
1095
1096void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1097 SkBaseDevice* dev = this->getTopDevice();
1098 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1099}
1100
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001101SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1102 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1103 if (NULL == fAddr) {
1104 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001105 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001106 return; // failure, fAddr is NULL
1107 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001108 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1109 return; // failure, fAddr is NULL
1110 }
1111 fAddr = fBitmap.getPixels();
1112 fRowBytes = fBitmap.rowBytes();
1113 }
1114 SkASSERT(fAddr); // success
1115}
1116
1117bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1118 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001119 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001120 } else {
1121 bitmap->reset();
1122 return false;
1123 }
1124}
1125
reed@android.com8a1c16f2008-12-17 15:59:43 +00001126/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001127void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001128 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001129 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001130 return;
1131 }
1132
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001133 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001134 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001135 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001136 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001137
1138 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001139
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001140 SkRect storage;
1141 const SkRect* bounds = NULL;
1142 if (paint && paint->canComputeFastBounds()) {
1143 bitmap.getBounds(&storage);
1144 matrix.mapRect(&storage);
1145 bounds = &paint->computeFastBounds(storage, &storage);
1146 }
1147
1148 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001149
1150 while (iter.next()) {
1151 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1152 }
1153
1154 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001155}
1156
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001157void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed@google.com8926b162012-03-23 15:36:36 +00001158 const SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001159 SkPaint tmp;
1160 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001161 paint = &tmp;
1162 }
reed@google.com4b226022011-01-11 18:32:13 +00001163
reed@google.com8926b162012-03-23 15:36:36 +00001164 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001165 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001166 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001167 paint = &looper.paint();
1168 SkImageFilter* filter = paint->getImageFilter();
1169 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001170 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001171 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001172 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001173 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001174 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001175 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001176 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001177 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001178 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001179 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001180 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001181 SkPaint tmpUnfiltered(*paint);
1182 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001183 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1184 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001185 }
1186 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001187 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001188 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001189 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001190 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001191}
1192
reed41af9662015-01-05 07:49:08 -08001193void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001194 if (gTreatSpriteAsBitmap) {
1195 this->save();
1196 this->resetMatrix();
1197 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1198 this->restore();
1199 return;
1200 }
1201
danakj9881d632014-11-26 12:41:06 -08001202 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001203 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001204 return;
1205 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001206 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001207
reed@google.com8926b162012-03-23 15:36:36 +00001208 SkPaint tmp;
1209 if (NULL == paint) {
1210 paint = &tmp;
1211 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001212
reed@google.com8926b162012-03-23 15:36:36 +00001213 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001214
reed@google.com8926b162012-03-23 15:36:36 +00001215 while (iter.next()) {
1216 paint = &looper.paint();
1217 SkImageFilter* filter = paint->getImageFilter();
1218 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1219 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001220 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001221 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001222 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001223 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001224 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001225 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001226 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001227 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001228 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001229 SkPaint tmpUnfiltered(*paint);
1230 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001231 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001232 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001233 }
1234 } else {
1235 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1236 }
1237 }
1238 LOOPER_END
1239}
1240
reed@android.com8a1c16f2008-12-17 15:59:43 +00001241/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001242void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001243 SkMatrix m;
1244 m.setTranslate(dx, dy);
1245 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001246}
1247
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001248void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001249 SkMatrix m;
1250 m.setScale(sx, sy);
1251 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001252}
1253
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001254void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001255 SkMatrix m;
1256 m.setRotate(degrees);
1257 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001258}
1259
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001260void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001261 SkMatrix m;
1262 m.setSkew(sx, sy);
1263 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001264}
1265
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001266void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001267 if (matrix.isIdentity()) {
1268 return;
1269 }
1270
reed2ff1fce2014-12-11 07:07:37 -08001271 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001273 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001274 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001275
1276 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001277}
1278
reed@android.com8a1c16f2008-12-17 15:59:43 +00001279void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001280 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001281 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001282 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001283 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001284 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001285}
1286
reed@android.com8a1c16f2008-12-17 15:59:43 +00001287void SkCanvas::resetMatrix() {
1288 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001289
reed@android.com8a1c16f2008-12-17 15:59:43 +00001290 matrix.reset();
1291 this->setMatrix(matrix);
1292}
1293
1294//////////////////////////////////////////////////////////////////////////////
1295
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001296void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001297 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001298 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1299 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001300}
1301
1302void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001303#ifdef SK_ENABLE_CLIP_QUICKREJECT
1304 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001305 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001306 return false;
1307 }
1308
reed@google.com3b3e8952012-08-16 20:53:31 +00001309 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001310 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001311 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001312
reed687fa1c2015-04-07 08:00:56 -07001313 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001314 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001315 }
1316 }
1317#endif
1318
reed@google.com5c3d1472011-02-22 19:12:23 +00001319 AutoValidateClip avc(this);
1320
reed@android.com8a1c16f2008-12-17 15:59:43 +00001321 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001322 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001323 if (!fAllowSoftClip) {
1324 edgeStyle = kHard_ClipEdgeStyle;
1325 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001326
reed1f836ee2014-07-07 07:49:34 -07001327 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001328 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001329 // the matrix. This means we don't have to a) make a path, and b) tell
1330 // the region code to scan-convert the path, only to discover that it
1331 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333
reed1f836ee2014-07-07 07:49:34 -07001334 fMCRec->fMatrix.mapRect(&r, rect);
reed687fa1c2015-04-07 08:00:56 -07001335 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001336 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001338 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001339 // and clip against that, since it can handle any matrix. However, to
1340 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1341 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001342 SkPath path;
1343
1344 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001345 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346 }
1347}
1348
reed73e714e2014-09-04 09:02:23 -07001349static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1350 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001351 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001352}
1353
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001354void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001355 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001356 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001357 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001358 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1359 } else {
1360 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001361 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001362}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001363
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001364void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001365 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001366 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001367 AutoValidateClip avc(this);
1368
1369 fDeviceCMDirty = true;
1370 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001371 if (!fAllowSoftClip) {
1372 edgeStyle = kHard_ClipEdgeStyle;
1373 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001374
reed687fa1c2015-04-07 08:00:56 -07001375 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001376
1377 SkPath devPath;
1378 devPath.addRRect(transformedRRect);
1379
reed73e714e2014-09-04 09:02:23 -07001380 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001381 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001382 }
1383
1384 SkPath path;
1385 path.addRRect(rrect);
1386 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001387 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001388}
1389
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001390void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001391 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001392 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1393 SkRect r;
1394 if (!path.isInverseFillType() && path.isRect(&r)) {
1395 this->onClipRect(r, op, edgeStyle);
1396 } else {
1397 this->onClipPath(path, op, edgeStyle);
1398 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001399}
1400
1401void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001402#ifdef SK_ENABLE_CLIP_QUICKREJECT
1403 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001404 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001405 return false;
1406 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001407
reed@google.com3b3e8952012-08-16 20:53:31 +00001408 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001409 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001410 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001411
reed687fa1c2015-04-07 08:00:56 -07001412 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001413 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001414 }
1415 }
1416#endif
1417
reed@google.com5c3d1472011-02-22 19:12:23 +00001418 AutoValidateClip avc(this);
1419
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001421 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001422 if (!fAllowSoftClip) {
1423 edgeStyle = kHard_ClipEdgeStyle;
1424 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001425
1426 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001427 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428
reed@google.comfe701122011-11-08 19:41:23 +00001429 // Check if the transfomation, or the original path itself
1430 // made us empty. Note this can also happen if we contained NaN
1431 // values. computing the bounds detects this, and will set our
1432 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1433 if (devPath.getBounds().isEmpty()) {
1434 // resetting the path will remove any NaN or other wanky values
1435 // that might upset our scan converter.
1436 devPath.reset();
1437 }
1438
reed@google.com5c3d1472011-02-22 19:12:23 +00001439 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001440 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001441
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001442 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001443 bool clipIsAA = getClipStack()->asPath(&devPath);
1444 if (clipIsAA) {
1445 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001446 }
fmalita1a481fe2015-02-04 07:39:34 -08001447
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001448 op = SkRegion::kReplace_Op;
1449 }
1450
reed73e714e2014-09-04 09:02:23 -07001451 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001452}
1453
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001454void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001455 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001456 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001457}
1458
1459void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001460 AutoValidateClip avc(this);
1461
reed@android.com8a1c16f2008-12-17 15:59:43 +00001462 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001463 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001464
reed@google.com5c3d1472011-02-22 19:12:23 +00001465 // todo: signal fClipStack that we have a region, and therefore (I guess)
1466 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001467 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001468
reed1f836ee2014-07-07 07:49:34 -07001469 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001470}
1471
reed@google.com819c9212011-02-23 18:56:55 +00001472#ifdef SK_DEBUG
1473void SkCanvas::validateClip() const {
1474 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001475 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001476 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001477 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001478 return;
1479 }
1480
reed@google.com819c9212011-02-23 18:56:55 +00001481 SkIRect ir;
1482 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001483 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001484
reed687fa1c2015-04-07 08:00:56 -07001485 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001486 const SkClipStack::Element* element;
1487 while ((element = iter.next()) != NULL) {
1488 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001489 case SkClipStack::Element::kRect_Type:
1490 element->getRect().round(&ir);
1491 tmpClip.op(ir, element->getOp());
1492 break;
1493 case SkClipStack::Element::kEmpty_Type:
1494 tmpClip.setEmpty();
1495 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001496 default: {
1497 SkPath path;
1498 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001499 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001500 break;
1501 }
reed@google.com819c9212011-02-23 18:56:55 +00001502 }
1503 }
reed@google.com819c9212011-02-23 18:56:55 +00001504}
1505#endif
1506
reed@google.com90c07ea2012-04-13 13:50:27 +00001507void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001508 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001509 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001510
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001511 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001512 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001513 }
1514}
1515
reed@google.com5c3d1472011-02-22 19:12:23 +00001516///////////////////////////////////////////////////////////////////////////////
1517
reed@google.com754de5f2014-02-24 19:38:20 +00001518bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001519 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001520}
1521
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001522bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001523 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001524}
1525
reed@google.com3b3e8952012-08-16 20:53:31 +00001526bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001527 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001528 return true;
1529
reed1f836ee2014-07-07 07:49:34 -07001530 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001531 return true;
1532 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001533
reed1f836ee2014-07-07 07:49:34 -07001534 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001535 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001536 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001537 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001538 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001539 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001540
reed@android.coma380ae42009-07-21 01:17:02 +00001541 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001542 // TODO: should we use | instead, or compare all 4 at once?
1543 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001544 return true;
1545 }
reed@google.comc0784db2013-12-13 21:16:12 +00001546 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001547 return true;
1548 }
1549 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001550 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001551}
1552
reed@google.com3b3e8952012-08-16 20:53:31 +00001553bool SkCanvas::quickReject(const SkPath& path) const {
1554 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001555}
1556
reed@google.com3b3e8952012-08-16 20:53:31 +00001557bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001558 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001559 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001560 return false;
1561 }
1562
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001563 SkMatrix inverse;
1564 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001565 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001566 if (bounds) {
1567 bounds->setEmpty();
1568 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001569 return false;
1570 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001571
bsalomon49f085d2014-09-05 13:34:00 -07001572 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001573 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001574 // adjust it outwards in case we are antialiasing
1575 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001576
reed@google.com8f4d2302013-12-17 16:44:46 +00001577 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1578 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001579 inverse.mapRect(bounds, r);
1580 }
1581 return true;
1582}
1583
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001584bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001585 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001586 if (clip.isEmpty()) {
1587 if (bounds) {
1588 bounds->setEmpty();
1589 }
1590 return false;
1591 }
1592
bsalomon49f085d2014-09-05 13:34:00 -07001593 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001594 *bounds = clip.getBounds();
1595 }
1596 return true;
1597}
1598
reed@android.com8a1c16f2008-12-17 15:59:43 +00001599const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001600 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001601}
1602
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001603const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001604 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001605}
1606
reed@google.com9c135db2014-03-12 18:28:35 +00001607GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1608 SkBaseDevice* dev = this->getTopDevice();
1609 return dev ? dev->accessRenderTarget() : NULL;
1610}
1611
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001612GrContext* SkCanvas::getGrContext() {
1613#if SK_SUPPORT_GPU
1614 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001615 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001616 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001617 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001618 return renderTarget->getContext();
1619 }
1620 }
1621#endif
1622
1623 return NULL;
1624
1625}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001626
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001627void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1628 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001629 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001630 if (outer.isEmpty()) {
1631 return;
1632 }
1633 if (inner.isEmpty()) {
1634 this->drawRRect(outer, paint);
1635 return;
1636 }
1637
1638 // We don't have this method (yet), but technically this is what we should
1639 // be able to assert...
1640 // SkASSERT(outer.contains(inner));
1641 //
1642 // For now at least check for containment of bounds
1643 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1644
1645 this->onDrawDRRect(outer, inner, paint);
1646}
1647
reed41af9662015-01-05 07:49:08 -08001648// These need to stop being virtual -- clients need to override the onDraw... versions
1649
1650void SkCanvas::drawPaint(const SkPaint& paint) {
1651 this->onDrawPaint(paint);
1652}
1653
1654void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1655 this->onDrawRect(r, paint);
1656}
1657
1658void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1659 this->onDrawOval(r, paint);
1660}
1661
1662void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1663 this->onDrawRRect(rrect, paint);
1664}
1665
1666void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1667 this->onDrawPoints(mode, count, pts, paint);
1668}
1669
1670void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1671 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1672 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1673 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1674 indices, indexCount, paint);
1675}
1676
1677void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1678 this->onDrawPath(path, paint);
1679}
1680
1681void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1682 this->onDrawImage(image, dx, dy, paint);
1683}
1684
1685void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1686 const SkPaint* paint) {
1687 this->onDrawImageRect(image, src, dst, paint);
1688}
1689
1690void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001691 if (bitmap.empty()) {
1692 return;
1693 }
reed41af9662015-01-05 07:49:08 -08001694 this->onDrawBitmap(bitmap, dx, dy, paint);
1695}
1696
1697void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1698 const SkPaint* paint, DrawBitmapRectFlags flags) {
tomhudson2df6fd62015-04-09 09:20:19 -07001699 if (bitmap.empty()) {
1700 return;
1701 }
reed41af9662015-01-05 07:49:08 -08001702 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1703}
1704
1705void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1706 const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001707 if (bitmap.empty()) {
1708 return;
1709 }
reed41af9662015-01-05 07:49:08 -08001710 this->onDrawBitmapNine(bitmap, center, dst, paint);
1711}
1712
1713void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001714 if (bitmap.empty()) {
1715 return;
1716 }
reed41af9662015-01-05 07:49:08 -08001717 this->onDrawSprite(bitmap, left, top, paint);
1718}
1719
reed@android.com8a1c16f2008-12-17 15:59:43 +00001720//////////////////////////////////////////////////////////////////////////////
1721// These are the virtual drawing methods
1722//////////////////////////////////////////////////////////////////////////////
1723
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001724void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001725 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001726 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1727 }
1728}
1729
reed41af9662015-01-05 07:49:08 -08001730void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001731 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001732 this->internalDrawPaint(paint);
1733}
1734
1735void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001736 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001737
1738 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001739 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001740 }
1741
reed@google.com4e2b3d32011-04-07 14:18:59 +00001742 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001743}
1744
reed41af9662015-01-05 07:49:08 -08001745void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1746 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001747 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001748 if ((long)count <= 0) {
1749 return;
1750 }
1751
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001752 SkRect r, storage;
1753 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001754 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001755 // special-case 2 points (common for drawing a single line)
1756 if (2 == count) {
1757 r.set(pts[0], pts[1]);
1758 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001759 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001760 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001761 bounds = &paint.computeFastStrokeBounds(r, &storage);
1762 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001763 return;
1764 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001765 }
reed@google.coma584aed2012-05-16 14:06:02 +00001766
reed@android.com8a1c16f2008-12-17 15:59:43 +00001767 SkASSERT(pts != NULL);
1768
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001769 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001770
reed@android.com8a1c16f2008-12-17 15:59:43 +00001771 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001772 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001773 }
reed@google.com4b226022011-01-11 18:32:13 +00001774
reed@google.com4e2b3d32011-04-07 14:18:59 +00001775 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001776}
1777
reed41af9662015-01-05 07:49:08 -08001778void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001779 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001780 SkRect storage;
1781 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001782 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001783 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1784 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1785 SkRect tmp(r);
1786 tmp.sort();
1787
1788 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001789 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001790 return;
1791 }
1792 }
reed@google.com4b226022011-01-11 18:32:13 +00001793
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001794 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001795
1796 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001797 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001798 }
1799
reed@google.com4e2b3d32011-04-07 14:18:59 +00001800 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001801}
1802
reed41af9662015-01-05 07:49:08 -08001803void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001804 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001805 SkRect storage;
1806 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001807 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001808 bounds = &paint.computeFastBounds(oval, &storage);
1809 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001810 return;
1811 }
1812 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001813
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001814 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001815
1816 while (iter.next()) {
1817 iter.fDevice->drawOval(iter, oval, looper.paint());
1818 }
1819
1820 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001821}
1822
reed41af9662015-01-05 07:49:08 -08001823void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001824 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001825 SkRect storage;
1826 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001827 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001828 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1829 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001830 return;
1831 }
1832 }
1833
1834 if (rrect.isRect()) {
1835 // call the non-virtual version
1836 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001837 return;
1838 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001839 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001840 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1841 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001842 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001843
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001844 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001845
1846 while (iter.next()) {
1847 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1848 }
1849
1850 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001851}
1852
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001853void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1854 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001855 SkRect storage;
1856 const SkRect* bounds = NULL;
1857 if (paint.canComputeFastBounds()) {
1858 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1859 if (this->quickReject(*bounds)) {
1860 return;
1861 }
1862 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001863
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001864 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001865
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001866 while (iter.next()) {
1867 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1868 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001869
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001870 LOOPER_END
1871}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001872
reed41af9662015-01-05 07:49:08 -08001873void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001874 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001875 if (!path.isFinite()) {
1876 return;
1877 }
1878
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001879 SkRect storage;
1880 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001881 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001882 const SkRect& pathBounds = path.getBounds();
1883 bounds = &paint.computeFastBounds(pathBounds, &storage);
1884 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001885 return;
1886 }
1887 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001888
1889 const SkRect& r = path.getBounds();
1890 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001891 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001892 this->internalDrawPaint(paint);
1893 }
1894 return;
1895 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001896
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001897 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001898
1899 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001900 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001901 }
1902
reed@google.com4e2b3d32011-04-07 14:18:59 +00001903 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001904}
1905
kkinnunena9baa652015-03-05 06:33:54 -08001906void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001907 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
kkinnunena9baa652015-03-05 06:33:54 -08001908 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001909}
1910
reed41af9662015-01-05 07:49:08 -08001911void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1912 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001913 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
kkinnunena9baa652015-03-05 06:33:54 -08001914 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001915}
1916
reed41af9662015-01-05 07:49:08 -08001917void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001918 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001919 SkDEBUGCODE(bitmap.validate();)
1920
reed@google.com3d608122011-11-21 15:16:16 +00001921 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001922 SkRect bounds = {
1923 x, y,
1924 x + SkIntToScalar(bitmap.width()),
1925 y + SkIntToScalar(bitmap.height())
1926 };
1927 if (paint) {
1928 (void)paint->computeFastBounds(bounds, &bounds);
1929 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001930 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001931 return;
1932 }
1933 }
reed@google.com4b226022011-01-11 18:32:13 +00001934
reed@android.com8a1c16f2008-12-17 15:59:43 +00001935 SkMatrix matrix;
1936 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001937 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001938}
1939
reed@google.com9987ec32011-09-07 11:57:52 +00001940// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00001941void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001942 const SkRect& dst, const SkPaint* paint,
1943 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001944 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001945 return;
1946 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001947
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001948 SkRect storage;
1949 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00001950 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001951 if (paint) {
1952 bounds = &paint->computeFastBounds(dst, &storage);
1953 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001954 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001955 return;
1956 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001957 }
reed@google.com3d608122011-11-21 15:16:16 +00001958
reed@google.com33535f32012-09-25 15:37:50 +00001959 SkLazyPaint lazy;
1960 if (NULL == paint) {
1961 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001962 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001963
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001964 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001965
reed@google.com33535f32012-09-25 15:37:50 +00001966 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001967 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00001968 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001969
reed@google.com33535f32012-09-25 15:37:50 +00001970 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001971}
1972
reed41af9662015-01-05 07:49:08 -08001973void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1974 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08001975 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00001976 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001977 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00001978}
1979
reed@google.com9987ec32011-09-07 11:57:52 +00001980void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1981 const SkIRect& center, const SkRect& dst,
1982 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001983 if (bitmap.drawsNothing()) {
1984 return;
1985 }
reed@google.com3d608122011-11-21 15:16:16 +00001986 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00001987 SkRect storage;
1988 const SkRect* bounds = &dst;
1989 if (paint) {
1990 bounds = &paint->computeFastBounds(dst, &storage);
1991 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001992 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001993 return;
1994 }
1995 }
1996
reed@google.com9987ec32011-09-07 11:57:52 +00001997 const int32_t w = bitmap.width();
1998 const int32_t h = bitmap.height();
1999
2000 SkIRect c = center;
2001 // pin center to the bounds of the bitmap
2002 c.fLeft = SkMax32(0, center.fLeft);
2003 c.fTop = SkMax32(0, center.fTop);
2004 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2005 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2006
reed@google.com71121732012-09-18 15:14:33 +00002007 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002008 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00002009 };
2010 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002011 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00002012 };
reed@google.com9987ec32011-09-07 11:57:52 +00002013 SkScalar dstX[4] = {
2014 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2015 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2016 };
2017 SkScalar dstY[4] = {
2018 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2019 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2020 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002021
reed@google.com9987ec32011-09-07 11:57:52 +00002022 if (dstX[1] > dstX[2]) {
2023 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2024 dstX[2] = dstX[1];
2025 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002026
reed@google.com9987ec32011-09-07 11:57:52 +00002027 if (dstY[1] > dstY[2]) {
2028 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2029 dstY[2] = dstY[1];
2030 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002031
reed@google.com9987ec32011-09-07 11:57:52 +00002032 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00002033 SkRect s, d;
2034
reed@google.com9987ec32011-09-07 11:57:52 +00002035 s.fTop = srcY[y];
2036 s.fBottom = srcY[y+1];
2037 d.fTop = dstY[y];
2038 d.fBottom = dstY[y+1];
2039 for (int x = 0; x < 3; x++) {
2040 s.fLeft = srcX[x];
2041 s.fRight = srcX[x+1];
2042 d.fLeft = dstX[x];
2043 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002044 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00002045 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00002046 }
2047 }
2048}
2049
reed41af9662015-01-05 07:49:08 -08002050void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2051 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002052 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002053 SkDEBUGCODE(bitmap.validate();)
2054
2055 // Need a device entry-point, so gpu can use a mesh
2056 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2057}
2058
reed@google.comf67e4cf2011-03-15 20:56:58 +00002059class SkDeviceFilteredPaint {
2060public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002061 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002062 uint32_t filteredFlags = device->filterTextFlags(paint);
2063 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002064 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002065 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002066 fPaint = newPaint;
2067 } else {
2068 fPaint = &paint;
2069 }
2070 }
2071
reed@google.comf67e4cf2011-03-15 20:56:58 +00002072 const SkPaint& paint() const { return *fPaint; }
2073
2074private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002075 const SkPaint* fPaint;
2076 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002077};
2078
bungeman@google.com52c748b2011-08-22 21:30:43 +00002079void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2080 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002081 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002082 draw.fDevice->drawRect(draw, r, paint);
2083 } else {
2084 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002085 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002086 draw.fDevice->drawRect(draw, r, p);
2087 }
2088}
2089
2090void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2091 const char text[], size_t byteLength,
2092 SkScalar x, SkScalar y) {
2093 SkASSERT(byteLength == 0 || text != NULL);
2094
2095 // nothing to draw
2096 if (text == NULL || byteLength == 0 ||
2097 draw.fClip->isEmpty() ||
2098 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2099 return;
2100 }
2101
2102 SkScalar width = 0;
2103 SkPoint start;
2104
2105 start.set(0, 0); // to avoid warning
2106 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2107 SkPaint::kStrikeThruText_Flag)) {
2108 width = paint.measureText(text, byteLength);
2109
2110 SkScalar offsetX = 0;
2111 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2112 offsetX = SkScalarHalf(width);
2113 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2114 offsetX = width;
2115 }
2116 start.set(x - offsetX, y);
2117 }
2118
2119 if (0 == width) {
2120 return;
2121 }
2122
2123 uint32_t flags = paint.getFlags();
2124
2125 if (flags & (SkPaint::kUnderlineText_Flag |
2126 SkPaint::kStrikeThruText_Flag)) {
2127 SkScalar textSize = paint.getTextSize();
2128 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2129 SkRect r;
2130
2131 r.fLeft = start.fX;
2132 r.fRight = start.fX + width;
2133
2134 if (flags & SkPaint::kUnderlineText_Flag) {
2135 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2136 start.fY);
2137 r.fTop = offset;
2138 r.fBottom = offset + height;
2139 DrawRect(draw, paint, r, textSize);
2140 }
2141 if (flags & SkPaint::kStrikeThruText_Flag) {
2142 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2143 start.fY);
2144 r.fTop = offset;
2145 r.fBottom = offset + height;
2146 DrawRect(draw, paint, r, textSize);
2147 }
2148 }
2149}
2150
reed@google.come0d9ce82014-04-23 04:00:17 +00002151void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2152 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002153 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002154
2155 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002156 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002157 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002158 DrawTextDecorations(iter, dfp.paint(),
2159 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002160 }
2161
reed@google.com4e2b3d32011-04-07 14:18:59 +00002162 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002163}
2164
reed@google.come0d9ce82014-04-23 04:00:17 +00002165void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2166 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002167 SkPoint textOffset = SkPoint::Make(0, 0);
2168
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002169 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002170
reed@android.com8a1c16f2008-12-17 15:59:43 +00002171 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002172 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002173 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002174 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002175 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002176
reed@google.com4e2b3d32011-04-07 14:18:59 +00002177 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002178}
2179
reed@google.come0d9ce82014-04-23 04:00:17 +00002180void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2181 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002182
2183 SkPoint textOffset = SkPoint::Make(0, constY);
2184
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002185 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002186
reed@android.com8a1c16f2008-12-17 15:59:43 +00002187 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002188 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002189 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002190 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002191 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002192
reed@google.com4e2b3d32011-04-07 14:18:59 +00002193 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002194}
2195
reed@google.come0d9ce82014-04-23 04:00:17 +00002196void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2197 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002198 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002199
reed@android.com8a1c16f2008-12-17 15:59:43 +00002200 while (iter.next()) {
2201 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002202 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002203 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002204
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002205 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002206}
2207
fmalita00d5c2c2014-08-21 08:53:26 -07002208void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2209 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002210
fmalita85d5eb92015-03-04 11:20:12 -08002211 SkRect storage;
2212 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002213 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002214 storage = blob->bounds().makeOffset(x, y);
2215 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002216
fmalita85d5eb92015-03-04 11:20:12 -08002217 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002218 return;
2219 }
2220 }
2221
fmalita024f9962015-03-03 19:08:17 -08002222 // We cannot filter in the looper as we normally do, because the paint is
2223 // incomplete at this point (text-related attributes are embedded within blob run paints).
2224 SkDrawFilter* drawFilter = fMCRec->fFilter;
2225 fMCRec->fFilter = NULL;
2226
fmalita85d5eb92015-03-04 11:20:12 -08002227 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002228
fmalitaaa1b9122014-08-28 14:32:24 -07002229 while (iter.next()) {
2230 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002231 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002232 }
2233
fmalitaaa1b9122014-08-28 14:32:24 -07002234 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002235
2236 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002237}
2238
reed@google.come0d9ce82014-04-23 04:00:17 +00002239// These will become non-virtual, so they always call the (virtual) onDraw... method
2240void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2241 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002242 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002243 this->onDrawText(text, byteLength, x, y, paint);
2244}
2245void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2246 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002247 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002248 this->onDrawPosText(text, byteLength, pos, paint);
2249}
2250void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2251 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002252 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002253 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2254}
2255void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2256 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002257 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002258 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2259}
fmalita00d5c2c2014-08-21 08:53:26 -07002260void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2261 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002262 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002263 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002264 this->onDrawTextBlob(blob, x, y, paint);
2265 }
2266}
reed@google.come0d9ce82014-04-23 04:00:17 +00002267
reed41af9662015-01-05 07:49:08 -08002268void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2269 const SkPoint verts[], const SkPoint texs[],
2270 const SkColor colors[], SkXfermode* xmode,
2271 const uint16_t indices[], int indexCount,
2272 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002273 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002274 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002275
reed@android.com8a1c16f2008-12-17 15:59:43 +00002276 while (iter.next()) {
2277 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002278 colors, xmode, indices, indexCount,
2279 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002280 }
reed@google.com4b226022011-01-11 18:32:13 +00002281
reed@google.com4e2b3d32011-04-07 14:18:59 +00002282 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002283}
2284
dandovb3c9d1c2014-08-12 08:34:29 -07002285void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2286 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002287 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002288 if (NULL == cubics) {
2289 return;
2290 }
mtklein6cfa73a2014-08-13 13:33:49 -07002291
dandovecfff212014-08-04 10:02:00 -07002292 // Since a patch is always within the convex hull of the control points, we discard it when its
2293 // bounding rectangle is completely outside the current clip.
2294 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002295 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002296 if (this->quickReject(bounds)) {
2297 return;
2298 }
mtklein6cfa73a2014-08-13 13:33:49 -07002299
dandovb3c9d1c2014-08-12 08:34:29 -07002300 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2301}
2302
2303void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2304 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2305
dandovecfff212014-08-04 10:02:00 -07002306 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002307
dandovecfff212014-08-04 10:02:00 -07002308 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002309 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002310 }
mtklein6cfa73a2014-08-13 13:33:49 -07002311
dandovecfff212014-08-04 10:02:00 -07002312 LOOPER_END
2313}
2314
reed3cb38402015-02-06 08:36:15 -08002315void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002316 if (dr && !this->quickReject(dr->getBounds())) {
2317 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002318 }
2319}
2320
reed3cb38402015-02-06 08:36:15 -08002321void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002322 dr->draw(this);
2323}
2324
reed@android.com8a1c16f2008-12-17 15:59:43 +00002325//////////////////////////////////////////////////////////////////////////////
2326// These methods are NOT virtual, and therefore must call back into virtual
2327// methods, rather than actually drawing themselves.
2328//////////////////////////////////////////////////////////////////////////////
2329
2330void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002331 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002332 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002333 SkPaint paint;
2334
2335 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002336 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002337 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002338 }
2339 this->drawPaint(paint);
2340}
2341
reed@android.com845fdac2009-06-23 03:01:32 +00002342void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002343 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002344 SkPaint paint;
2345
2346 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002347 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002348 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002349 }
2350 this->drawPaint(paint);
2351}
2352
2353void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002354 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002355 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002356
reed@android.com8a1c16f2008-12-17 15:59:43 +00002357 pt.set(x, y);
2358 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2359}
2360
2361void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002362 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002363 SkPoint pt;
2364 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002365
reed@android.com8a1c16f2008-12-17 15:59:43 +00002366 pt.set(x, y);
2367 paint.setColor(color);
2368 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2369}
2370
2371void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2372 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002373 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002374 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002375
reed@android.com8a1c16f2008-12-17 15:59:43 +00002376 pts[0].set(x0, y0);
2377 pts[1].set(x1, y1);
2378 this->drawPoints(kLines_PointMode, 2, pts, paint);
2379}
2380
2381void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2382 SkScalar right, SkScalar bottom,
2383 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002384 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002385 SkRect r;
2386
2387 r.set(left, top, right, bottom);
2388 this->drawRect(r, paint);
2389}
2390
2391void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2392 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002393 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002394 if (radius < 0) {
2395 radius = 0;
2396 }
2397
2398 SkRect r;
2399 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002400 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002401}
2402
2403void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2404 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002405 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002406 if (rx > 0 && ry > 0) {
2407 if (paint.canComputeFastBounds()) {
2408 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002409 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002410 return;
2411 }
2412 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002413 SkRRect rrect;
2414 rrect.setRectXY(r, rx, ry);
2415 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002416 } else {
2417 this->drawRect(r, paint);
2418 }
2419}
2420
reed@android.com8a1c16f2008-12-17 15:59:43 +00002421void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2422 SkScalar sweepAngle, bool useCenter,
2423 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002424 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002425 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2426 this->drawOval(oval, paint);
2427 } else {
2428 SkPath path;
2429 if (useCenter) {
2430 path.moveTo(oval.centerX(), oval.centerY());
2431 }
2432 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2433 if (useCenter) {
2434 path.close();
2435 }
2436 this->drawPath(path, paint);
2437 }
2438}
2439
2440void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2441 const SkPath& path, SkScalar hOffset,
2442 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002443 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002444 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002445
reed@android.com8a1c16f2008-12-17 15:59:43 +00002446 matrix.setTranslate(hOffset, vOffset);
2447 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2448}
2449
reed@android.comf76bacf2009-05-13 14:00:33 +00002450///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002451void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002452 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002453 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002454 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002455 }
2456}
2457
reedd5fa1a42014-08-09 11:08:05 -07002458void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002459 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002460 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002461 if (matrix && matrix->isIdentity()) {
2462 matrix = NULL;
2463 }
2464 this->onDrawPicture(picture, matrix, paint);
2465 }
2466}
robertphillips9b14f262014-06-04 05:40:44 -07002467
reedd5fa1a42014-08-09 11:08:05 -07002468void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2469 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002470 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002471 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002472 // Canvas has to first give the device the opportunity to render
2473 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002474 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002475 return; // the device has rendered the entire picture
2476 }
2477 }
2478
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002479 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002480
robertphillipsc5ba71d2014-09-04 08:42:50 -07002481 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482}
2483
reed@android.com8a1c16f2008-12-17 15:59:43 +00002484///////////////////////////////////////////////////////////////////////////////
2485///////////////////////////////////////////////////////////////////////////////
2486
2487SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002488 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002489
2490 SkASSERT(canvas);
2491
2492 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2493 fDone = !fImpl->next();
2494}
2495
2496SkCanvas::LayerIter::~LayerIter() {
2497 fImpl->~SkDrawIter();
2498}
2499
2500void SkCanvas::LayerIter::next() {
2501 fDone = !fImpl->next();
2502}
2503
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002504SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002505 return fImpl->getDevice();
2506}
2507
2508const SkMatrix& SkCanvas::LayerIter::matrix() const {
2509 return fImpl->getMatrix();
2510}
2511
2512const SkPaint& SkCanvas::LayerIter::paint() const {
2513 const SkPaint* paint = fImpl->getPaint();
2514 if (NULL == paint) {
2515 paint = &fDefaultPaint;
2516 }
2517 return *paint;
2518}
2519
2520const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2521int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2522int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002523
2524///////////////////////////////////////////////////////////////////////////////
2525
fmalitac3b589a2014-06-05 12:40:07 -07002526SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002527
2528///////////////////////////////////////////////////////////////////////////////
2529
2530static bool supported_for_raster_canvas(const SkImageInfo& info) {
2531 switch (info.alphaType()) {
2532 case kPremul_SkAlphaType:
2533 case kOpaque_SkAlphaType:
2534 break;
2535 default:
2536 return false;
2537 }
2538
2539 switch (info.colorType()) {
2540 case kAlpha_8_SkColorType:
2541 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002542 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002543 break;
2544 default:
2545 return false;
2546 }
2547
2548 return true;
2549}
2550
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002551SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2552 if (!supported_for_raster_canvas(info)) {
2553 return NULL;
2554 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002555
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002556 SkBitmap bitmap;
2557 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2558 return NULL;
2559 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002560 return SkNEW_ARGS(SkCanvas, (bitmap));
2561}
reedd5fa1a42014-08-09 11:08:05 -07002562
2563///////////////////////////////////////////////////////////////////////////////
2564
2565SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002566 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002567 : fCanvas(canvas)
2568 , fSaveCount(canvas->getSaveCount())
2569{
bsalomon49f085d2014-09-05 13:34:00 -07002570 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002571 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002572 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002573 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002574 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002575 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002576 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002577 canvas->save();
2578 }
mtklein6cfa73a2014-08-13 13:33:49 -07002579
bsalomon49f085d2014-09-05 13:34:00 -07002580 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002581 canvas->concat(*matrix);
2582 }
2583}
2584
2585SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2586 fCanvas->restoreToCount(fSaveCount);
2587}