blob: fbf6c9e83b904acc7df0b08a8b245097d768002d [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@google.com6f8f2922011-03-04 22:27:10 +0000114 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700115 const SkMatrix* fMatrix;
116 SkMatrix fMatrixStorage;
117 const bool fDeviceIsBitmapDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118
reed96e657d2015-03-10 17:30:07 -0700119 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed61f501f2015-04-29 08:34:00 -0700120 bool conservativeRasterClip, bool deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700121 : fNext(NULL)
122 , fClip(conservativeRasterClip)
reed61f501f2015-04-29 08:34:00 -0700123 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700124 {
125 if (NULL != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000127 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 }
reed@google.com4b226022011-01-11 18:32:13 +0000129 fDevice = device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000131 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000133 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700134 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000135 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 fDevice->unref();
137 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000138 SkDELETE(fPaint);
139 }
reed@google.com4b226022011-01-11 18:32:13 +0000140
mtkleinfeaadee2015-04-08 11:25:48 -0700141 void reset(const SkIRect& bounds) {
142 SkASSERT(!fPaint);
143 SkASSERT(!fNext);
144 SkASSERT(fDevice);
145 fClip.setRect(bounds);
146 }
147
reed@google.com045e62d2011-10-24 12:19:46 +0000148 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
149 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000150 int x = fDevice->getOrigin().x();
151 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 int width = fDevice->width();
153 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000154
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155 if ((x | y) == 0) {
156 fMatrix = &totalMatrix;
157 fClip = totalClip;
158 } else {
159 fMatrixStorage = totalMatrix;
160 fMatrixStorage.postTranslate(SkIntToScalar(-x),
161 SkIntToScalar(-y));
162 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000163
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164 totalClip.translate(-x, -y, &fClip);
165 }
166
reed@google.com045e62d2011-10-24 12:19:46 +0000167 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168
169 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000170
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000172 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173 SkRegion::kDifference_Op);
174 }
reed@google.com4b226022011-01-11 18:32:13 +0000175
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000176 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
177
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178#ifdef SK_DEBUG
179 if (!fClip.isEmpty()) {
180 SkIRect deviceR;
181 deviceR.set(0, 0, width, height);
182 SkASSERT(deviceR.contains(fClip.getBounds()));
183 }
184#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000185 }
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;
reed61f501f2015-04-29 08:34:00 -0700489 new (fBaseLayerStorage) DeviceCM(NULL, NULL, NULL, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700490
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
reed61f501f2015-04-29 08:34:00 -0700988 bool forceSpriteOnRestore = false;
989 {
990 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
991 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo);
992 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
993 if (NULL == newDev) {
994 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
995 newDev = SkBitmapDevice::Create(createInfo.fInfo);
996 if (NULL == newDev) {
997 SkErrorInternals::SetError(kInternalError_SkError,
998 "Unable to create device for layer.");
999 return;
1000 }
1001 forceSpriteOnRestore = true;
1002 }
1003 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001004 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001005
reed@google.com6f8f2922011-03-04 22:27:10 +00001006 device->setOrigin(ir.fLeft, ir.fTop);
reed61f501f2015-04-29 08:34:00 -07001007 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip,
1008 forceSpriteOnRestore));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001009 device->unref();
1010
1011 layer->fNext = fMCRec->fTopLayer;
1012 fMCRec->fLayer = layer;
1013 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001014}
1015
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001016int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1017 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1018}
1019
reed@android.com8a1c16f2008-12-17 15:59:43 +00001020int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1021 SaveFlags flags) {
1022 if (0xFF == alpha) {
1023 return this->saveLayer(bounds, NULL, flags);
1024 } else {
1025 SkPaint tmpPaint;
1026 tmpPaint.setAlpha(alpha);
1027 return this->saveLayer(bounds, &tmpPaint, flags);
1028 }
1029}
1030
reed@android.com8a1c16f2008-12-17 15:59:43 +00001031void SkCanvas::internalRestore() {
1032 SkASSERT(fMCStack.count() != 0);
1033
1034 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001035 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001036
reed687fa1c2015-04-07 08:00:56 -07001037 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001038
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001039 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001040 DeviceCM* layer = fMCRec->fLayer; // may be null
1041 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1042 fMCRec->fLayer = NULL;
1043
1044 // now do the normal restore()
1045 fMCRec->~MCRec(); // balanced in save()
1046 fMCStack.pop_back();
1047 fMCRec = (MCRec*)fMCStack.back();
1048
1049 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1050 since if we're being recorded, we don't want to record this (the
1051 recorder will have already recorded the restore).
1052 */
bsalomon49f085d2014-09-05 13:34:00 -07001053 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001055 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001056 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001057 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001058 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059 fDeviceCMDirty = true;
reedb679ca82015-04-07 04:40:48 -07001060 SkDELETE(layer);
1061 } else {
1062 // we're at the root
1063 SkASSERT(layer == (void*)fBaseLayerStorage);
1064 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001065 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001066 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067}
1068
reed4a8126e2014-09-22 07:29:03 -07001069SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1070 if (NULL == props) {
1071 props = &fProps;
1072 }
1073 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001074}
1075
reed4a8126e2014-09-22 07:29:03 -07001076SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001077 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001078 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001079}
1080
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001081SkImageInfo SkCanvas::imageInfo() const {
1082 SkBaseDevice* dev = this->getDevice();
1083 if (dev) {
1084 return dev->imageInfo();
1085 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001086 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001087 }
1088}
1089
1090const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1091 return this->onPeekPixels(info, rowBytes);
1092}
1093
1094const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1095 SkBaseDevice* dev = this->getDevice();
1096 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1097}
1098
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001099void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1100 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1101 if (pixels && origin) {
1102 *origin = this->getTopDevice(false)->getOrigin();
1103 }
1104 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001105}
1106
1107void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1108 SkBaseDevice* dev = this->getTopDevice();
1109 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1110}
1111
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001112SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1113 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1114 if (NULL == fAddr) {
1115 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001116 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001117 return; // failure, fAddr is NULL
1118 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001119 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1120 return; // failure, fAddr is NULL
1121 }
1122 fAddr = fBitmap.getPixels();
1123 fRowBytes = fBitmap.rowBytes();
1124 }
1125 SkASSERT(fAddr); // success
1126}
1127
1128bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1129 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001130 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001131 } else {
1132 bitmap->reset();
1133 return false;
1134 }
1135}
1136
reed@android.com8a1c16f2008-12-17 15:59:43 +00001137/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001138void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001139 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001140 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001141 return;
1142 }
1143
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001144 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001145 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001146 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001147 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001148
1149 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001150
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001151 SkRect storage;
1152 const SkRect* bounds = NULL;
1153 if (paint && paint->canComputeFastBounds()) {
1154 bitmap.getBounds(&storage);
1155 matrix.mapRect(&storage);
1156 bounds = &paint->computeFastBounds(storage, &storage);
1157 }
1158
1159 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001160
1161 while (iter.next()) {
1162 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1163 }
1164
1165 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001166}
1167
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001168void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001169 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001170 SkPaint tmp;
1171 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001172 paint = &tmp;
1173 }
reed@google.com4b226022011-01-11 18:32:13 +00001174
reed@google.com8926b162012-03-23 15:36:36 +00001175 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001176 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001177 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001178 paint = &looper.paint();
1179 SkImageFilter* filter = paint->getImageFilter();
1180 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001181 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001182 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001183 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001184 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001185 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001186 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001187 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001188 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001189 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001190 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001191 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001192 SkPaint tmpUnfiltered(*paint);
1193 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001194 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1195 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001196 }
reed61f501f2015-04-29 08:34:00 -07001197 } else if (deviceIsBitmapDevice) {
1198 const SkBitmap& src = srcDev->accessBitmap(false);
1199 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001200 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001201 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001202 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001203 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001204 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001205}
1206
reed41af9662015-01-05 07:49:08 -08001207void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001208 if (gTreatSpriteAsBitmap) {
1209 this->save();
1210 this->resetMatrix();
1211 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1212 this->restore();
1213 return;
1214 }
1215
danakj9881d632014-11-26 12:41:06 -08001216 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001217 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001218 return;
1219 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001220 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001221
reed@google.com8926b162012-03-23 15:36:36 +00001222 SkPaint tmp;
1223 if (NULL == paint) {
1224 paint = &tmp;
1225 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001226
reed@google.com8926b162012-03-23 15:36:36 +00001227 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001228
reed@google.com8926b162012-03-23 15:36:36 +00001229 while (iter.next()) {
1230 paint = &looper.paint();
1231 SkImageFilter* filter = paint->getImageFilter();
1232 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1233 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001234 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001235 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001236 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001237 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001238 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001239 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001240 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001241 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001242 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001243 SkPaint tmpUnfiltered(*paint);
1244 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001245 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001246 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001247 }
1248 } else {
1249 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1250 }
1251 }
1252 LOOPER_END
1253}
1254
reed@android.com8a1c16f2008-12-17 15:59:43 +00001255/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001256void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001257 SkMatrix m;
1258 m.setTranslate(dx, dy);
1259 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001260}
1261
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001262void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001263 SkMatrix m;
1264 m.setScale(sx, sy);
1265 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266}
1267
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001268void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001269 SkMatrix m;
1270 m.setRotate(degrees);
1271 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272}
1273
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001274void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001275 SkMatrix m;
1276 m.setSkew(sx, sy);
1277 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001278}
1279
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001280void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001281 if (matrix.isIdentity()) {
1282 return;
1283 }
1284
reed2ff1fce2014-12-11 07:07:37 -08001285 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001286 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001287 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001288 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001289
1290 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001291}
1292
reed@android.com8a1c16f2008-12-17 15:59:43 +00001293void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001294 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001295 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001296 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001297 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001298 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001299}
1300
reed@android.com8a1c16f2008-12-17 15:59:43 +00001301void SkCanvas::resetMatrix() {
1302 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001303
reed@android.com8a1c16f2008-12-17 15:59:43 +00001304 matrix.reset();
1305 this->setMatrix(matrix);
1306}
1307
1308//////////////////////////////////////////////////////////////////////////////
1309
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001310void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001311 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001312 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1313 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001314}
1315
1316void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001317#ifdef SK_ENABLE_CLIP_QUICKREJECT
1318 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001319 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001320 return false;
1321 }
1322
reed@google.com3b3e8952012-08-16 20:53:31 +00001323 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001324 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001325 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001326
reed687fa1c2015-04-07 08:00:56 -07001327 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001328 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001329 }
1330 }
1331#endif
1332
reed@google.com5c3d1472011-02-22 19:12:23 +00001333 AutoValidateClip avc(this);
1334
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001336 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001337 if (!fAllowSoftClip) {
1338 edgeStyle = kHard_ClipEdgeStyle;
1339 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340
reed1f836ee2014-07-07 07:49:34 -07001341 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001342 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001343 // the matrix. This means we don't have to a) make a path, and b) tell
1344 // the region code to scan-convert the path, only to discover that it
1345 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001347
reed1f836ee2014-07-07 07:49:34 -07001348 fMCRec->fMatrix.mapRect(&r, rect);
reed687fa1c2015-04-07 08:00:56 -07001349 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001350 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001351 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001352 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001353 // and clip against that, since it can handle any matrix. However, to
1354 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1355 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001356 SkPath path;
1357
1358 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001359 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001360 }
1361}
1362
reed73e714e2014-09-04 09:02:23 -07001363static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1364 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001365 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001366}
1367
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001368void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001369 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001370 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001371 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001372 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1373 } else {
1374 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001375 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001376}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001377
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001378void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001379 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001380 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001381 AutoValidateClip avc(this);
1382
1383 fDeviceCMDirty = true;
1384 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001385 if (!fAllowSoftClip) {
1386 edgeStyle = kHard_ClipEdgeStyle;
1387 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001388
reed687fa1c2015-04-07 08:00:56 -07001389 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001390
1391 SkPath devPath;
1392 devPath.addRRect(transformedRRect);
1393
reed73e714e2014-09-04 09:02:23 -07001394 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001395 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001396 }
1397
1398 SkPath path;
1399 path.addRRect(rrect);
1400 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001401 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001402}
1403
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001404void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001405 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001406 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1407 SkRect r;
1408 if (!path.isInverseFillType() && path.isRect(&r)) {
1409 this->onClipRect(r, op, edgeStyle);
1410 } else {
1411 this->onClipPath(path, op, edgeStyle);
1412 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001413}
1414
1415void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001416#ifdef SK_ENABLE_CLIP_QUICKREJECT
1417 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001418 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001419 return false;
1420 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001421
reed@google.com3b3e8952012-08-16 20:53:31 +00001422 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001423 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001424 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001425
reed687fa1c2015-04-07 08:00:56 -07001426 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001427 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001428 }
1429 }
1430#endif
1431
reed@google.com5c3d1472011-02-22 19:12:23 +00001432 AutoValidateClip avc(this);
1433
reed@android.com8a1c16f2008-12-17 15:59:43 +00001434 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001435 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001436 if (!fAllowSoftClip) {
1437 edgeStyle = kHard_ClipEdgeStyle;
1438 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001439
1440 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001441 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001442
reed@google.comfe701122011-11-08 19:41:23 +00001443 // Check if the transfomation, or the original path itself
1444 // made us empty. Note this can also happen if we contained NaN
1445 // values. computing the bounds detects this, and will set our
1446 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1447 if (devPath.getBounds().isEmpty()) {
1448 // resetting the path will remove any NaN or other wanky values
1449 // that might upset our scan converter.
1450 devPath.reset();
1451 }
1452
reed@google.com5c3d1472011-02-22 19:12:23 +00001453 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001454 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001455
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001456 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001457 bool clipIsAA = getClipStack()->asPath(&devPath);
1458 if (clipIsAA) {
1459 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001460 }
fmalita1a481fe2015-02-04 07:39:34 -08001461
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001462 op = SkRegion::kReplace_Op;
1463 }
1464
reed73e714e2014-09-04 09:02:23 -07001465 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001466}
1467
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001468void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001469 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001470 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001471}
1472
1473void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001474 AutoValidateClip avc(this);
1475
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001477 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001478
reed@google.com5c3d1472011-02-22 19:12:23 +00001479 // todo: signal fClipStack that we have a region, and therefore (I guess)
1480 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001481 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001482
reed1f836ee2014-07-07 07:49:34 -07001483 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001484}
1485
reed@google.com819c9212011-02-23 18:56:55 +00001486#ifdef SK_DEBUG
1487void SkCanvas::validateClip() const {
1488 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001489 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001490 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001491 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001492 return;
1493 }
1494
reed@google.com819c9212011-02-23 18:56:55 +00001495 SkIRect ir;
1496 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001497 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001498
reed687fa1c2015-04-07 08:00:56 -07001499 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001500 const SkClipStack::Element* element;
1501 while ((element = iter.next()) != NULL) {
1502 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001503 case SkClipStack::Element::kRect_Type:
1504 element->getRect().round(&ir);
1505 tmpClip.op(ir, element->getOp());
1506 break;
1507 case SkClipStack::Element::kEmpty_Type:
1508 tmpClip.setEmpty();
1509 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001510 default: {
1511 SkPath path;
1512 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001513 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001514 break;
1515 }
reed@google.com819c9212011-02-23 18:56:55 +00001516 }
1517 }
reed@google.com819c9212011-02-23 18:56:55 +00001518}
1519#endif
1520
reed@google.com90c07ea2012-04-13 13:50:27 +00001521void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001522 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001523 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001524
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001525 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001526 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001527 }
1528}
1529
reed@google.com5c3d1472011-02-22 19:12:23 +00001530///////////////////////////////////////////////////////////////////////////////
1531
reed@google.com754de5f2014-02-24 19:38:20 +00001532bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001533 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001534}
1535
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001536bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001537 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001538}
1539
reed@google.com3b3e8952012-08-16 20:53:31 +00001540bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001541 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001542 return true;
1543
reed1f836ee2014-07-07 07:49:34 -07001544 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001545 return true;
1546 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001547
reed1f836ee2014-07-07 07:49:34 -07001548 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001549 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001550 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001551 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001552 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001553 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001554
reed@android.coma380ae42009-07-21 01:17:02 +00001555 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001556 // TODO: should we use | instead, or compare all 4 at once?
1557 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001558 return true;
1559 }
reed@google.comc0784db2013-12-13 21:16:12 +00001560 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001561 return true;
1562 }
1563 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001564 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001565}
1566
reed@google.com3b3e8952012-08-16 20:53:31 +00001567bool SkCanvas::quickReject(const SkPath& path) const {
1568 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001569}
1570
reed@google.com3b3e8952012-08-16 20:53:31 +00001571bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001572 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001573 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001574 return false;
1575 }
1576
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001577 SkMatrix inverse;
1578 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001579 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001580 if (bounds) {
1581 bounds->setEmpty();
1582 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001583 return false;
1584 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001585
bsalomon49f085d2014-09-05 13:34:00 -07001586 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001587 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001588 // adjust it outwards in case we are antialiasing
1589 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001590
reed@google.com8f4d2302013-12-17 16:44:46 +00001591 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1592 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001593 inverse.mapRect(bounds, r);
1594 }
1595 return true;
1596}
1597
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001598bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001599 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001600 if (clip.isEmpty()) {
1601 if (bounds) {
1602 bounds->setEmpty();
1603 }
1604 return false;
1605 }
1606
bsalomon49f085d2014-09-05 13:34:00 -07001607 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001608 *bounds = clip.getBounds();
1609 }
1610 return true;
1611}
1612
reed@android.com8a1c16f2008-12-17 15:59:43 +00001613const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001614 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001615}
1616
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001617const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001618 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001619}
1620
reed@google.com9c135db2014-03-12 18:28:35 +00001621GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1622 SkBaseDevice* dev = this->getTopDevice();
1623 return dev ? dev->accessRenderTarget() : NULL;
1624}
1625
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001626GrContext* SkCanvas::getGrContext() {
1627#if SK_SUPPORT_GPU
1628 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001629 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001630 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001631 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001632 return renderTarget->getContext();
1633 }
1634 }
1635#endif
1636
1637 return NULL;
1638
1639}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001640
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001641void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1642 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001643 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001644 if (outer.isEmpty()) {
1645 return;
1646 }
1647 if (inner.isEmpty()) {
1648 this->drawRRect(outer, paint);
1649 return;
1650 }
1651
1652 // We don't have this method (yet), but technically this is what we should
1653 // be able to assert...
1654 // SkASSERT(outer.contains(inner));
1655 //
1656 // For now at least check for containment of bounds
1657 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1658
1659 this->onDrawDRRect(outer, inner, paint);
1660}
1661
reed41af9662015-01-05 07:49:08 -08001662// These need to stop being virtual -- clients need to override the onDraw... versions
1663
1664void SkCanvas::drawPaint(const SkPaint& paint) {
1665 this->onDrawPaint(paint);
1666}
1667
1668void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1669 this->onDrawRect(r, paint);
1670}
1671
1672void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1673 this->onDrawOval(r, paint);
1674}
1675
1676void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1677 this->onDrawRRect(rrect, paint);
1678}
1679
1680void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1681 this->onDrawPoints(mode, count, pts, paint);
1682}
1683
1684void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1685 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1686 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1687 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1688 indices, indexCount, paint);
1689}
1690
1691void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1692 this->onDrawPath(path, paint);
1693}
1694
1695void SkCanvas::drawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1696 this->onDrawImage(image, dx, dy, paint);
1697}
1698
1699void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1700 const SkPaint* paint) {
1701 this->onDrawImageRect(image, src, dst, paint);
1702}
1703
1704void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001705 if (bitmap.empty()) {
1706 return;
1707 }
reed41af9662015-01-05 07:49:08 -08001708 this->onDrawBitmap(bitmap, dx, dy, paint);
1709}
1710
1711void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1712 const SkPaint* paint, DrawBitmapRectFlags flags) {
tomhudson2df6fd62015-04-09 09:20:19 -07001713 if (bitmap.empty()) {
1714 return;
1715 }
reed41af9662015-01-05 07:49:08 -08001716 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1717}
1718
1719void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1720 const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001721 if (bitmap.empty()) {
1722 return;
1723 }
reed41af9662015-01-05 07:49:08 -08001724 this->onDrawBitmapNine(bitmap, center, dst, paint);
1725}
1726
1727void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001728 if (bitmap.empty()) {
1729 return;
1730 }
reed41af9662015-01-05 07:49:08 -08001731 this->onDrawSprite(bitmap, left, top, paint);
1732}
1733
reed@android.com8a1c16f2008-12-17 15:59:43 +00001734//////////////////////////////////////////////////////////////////////////////
1735// These are the virtual drawing methods
1736//////////////////////////////////////////////////////////////////////////////
1737
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001738void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001739 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001740 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1741 }
1742}
1743
reed41af9662015-01-05 07:49:08 -08001744void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001745 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001746 this->internalDrawPaint(paint);
1747}
1748
1749void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001750 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001751
1752 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001753 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001754 }
1755
reed@google.com4e2b3d32011-04-07 14:18:59 +00001756 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001757}
1758
reed41af9662015-01-05 07:49:08 -08001759void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1760 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001761 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001762 if ((long)count <= 0) {
1763 return;
1764 }
1765
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001766 SkRect r, storage;
1767 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001768 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001769 // special-case 2 points (common for drawing a single line)
1770 if (2 == count) {
1771 r.set(pts[0], pts[1]);
1772 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001773 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001774 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001775 bounds = &paint.computeFastStrokeBounds(r, &storage);
1776 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001777 return;
1778 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001779 }
reed@google.coma584aed2012-05-16 14:06:02 +00001780
reed@android.com8a1c16f2008-12-17 15:59:43 +00001781 SkASSERT(pts != NULL);
1782
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001783 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001784
reed@android.com8a1c16f2008-12-17 15:59:43 +00001785 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001786 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001787 }
reed@google.com4b226022011-01-11 18:32:13 +00001788
reed@google.com4e2b3d32011-04-07 14:18:59 +00001789 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001790}
1791
reed41af9662015-01-05 07:49:08 -08001792void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001793 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001794 SkRect storage;
1795 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001796 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001797 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1798 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1799 SkRect tmp(r);
1800 tmp.sort();
1801
1802 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001803 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001804 return;
1805 }
1806 }
reed@google.com4b226022011-01-11 18:32:13 +00001807
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001808 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001809
1810 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001811 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001812 }
1813
reed@google.com4e2b3d32011-04-07 14:18:59 +00001814 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001815}
1816
reed41af9662015-01-05 07:49:08 -08001817void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001818 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001819 SkRect storage;
1820 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001821 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001822 bounds = &paint.computeFastBounds(oval, &storage);
1823 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001824 return;
1825 }
1826 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001827
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001828 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001829
1830 while (iter.next()) {
1831 iter.fDevice->drawOval(iter, oval, looper.paint());
1832 }
1833
1834 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001835}
1836
reed41af9662015-01-05 07:49:08 -08001837void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001838 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001839 SkRect storage;
1840 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001841 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001842 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1843 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001844 return;
1845 }
1846 }
1847
1848 if (rrect.isRect()) {
1849 // call the non-virtual version
1850 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001851 return;
1852 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001853 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001854 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1855 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001856 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001857
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001858 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001859
1860 while (iter.next()) {
1861 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1862 }
1863
1864 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001865}
1866
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001867void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1868 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001869 SkRect storage;
1870 const SkRect* bounds = NULL;
1871 if (paint.canComputeFastBounds()) {
1872 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1873 if (this->quickReject(*bounds)) {
1874 return;
1875 }
1876 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001877
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001878 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001879
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001880 while (iter.next()) {
1881 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1882 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001883
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001884 LOOPER_END
1885}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001886
reed41af9662015-01-05 07:49:08 -08001887void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001888 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001889 if (!path.isFinite()) {
1890 return;
1891 }
1892
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001893 SkRect storage;
1894 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001895 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001896 const SkRect& pathBounds = path.getBounds();
1897 bounds = &paint.computeFastBounds(pathBounds, &storage);
1898 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001899 return;
1900 }
1901 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001902
1903 const SkRect& r = path.getBounds();
1904 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001905 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001906 this->internalDrawPaint(paint);
1907 }
1908 return;
1909 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001910
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001911 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001912
1913 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001914 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001915 }
1916
reed@google.com4e2b3d32011-04-07 14:18:59 +00001917 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001918}
1919
kkinnunena9baa652015-03-05 06:33:54 -08001920void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001921 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
kkinnunena9baa652015-03-05 06:33:54 -08001922 image->draw(this, dx, dy, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001923}
1924
reed41af9662015-01-05 07:49:08 -08001925void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1926 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001927 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
kkinnunena9baa652015-03-05 06:33:54 -08001928 image->drawRect(this, src, dst, paint);
piotaixrb5fae932014-09-24 13:03:30 -07001929}
1930
reed41af9662015-01-05 07:49:08 -08001931void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001932 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00001933 SkDEBUGCODE(bitmap.validate();)
1934
reed@google.com3d608122011-11-21 15:16:16 +00001935 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001936 SkRect bounds = {
1937 x, y,
1938 x + SkIntToScalar(bitmap.width()),
1939 y + SkIntToScalar(bitmap.height())
1940 };
1941 if (paint) {
1942 (void)paint->computeFastBounds(bounds, &bounds);
1943 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001944 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001945 return;
1946 }
1947 }
reed@google.com4b226022011-01-11 18:32:13 +00001948
reed@android.com8a1c16f2008-12-17 15:59:43 +00001949 SkMatrix matrix;
1950 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001951 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001952}
1953
reed@google.com9987ec32011-09-07 11:57:52 +00001954// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00001955void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001956 const SkRect& dst, const SkPaint* paint,
1957 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001958 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001959 return;
1960 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00001961
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001962 SkRect storage;
1963 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00001964 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00001965 if (paint) {
1966 bounds = &paint->computeFastBounds(dst, &storage);
1967 }
reed@google.com3b3e8952012-08-16 20:53:31 +00001968 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00001969 return;
1970 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001971 }
reed@google.com3d608122011-11-21 15:16:16 +00001972
reed@google.com33535f32012-09-25 15:37:50 +00001973 SkLazyPaint lazy;
1974 if (NULL == paint) {
1975 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001976 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001977
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001978 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001979
reed@google.com33535f32012-09-25 15:37:50 +00001980 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001981 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00001982 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00001983
reed@google.com33535f32012-09-25 15:37:50 +00001984 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001985}
1986
reed41af9662015-01-05 07:49:08 -08001987void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1988 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08001989 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00001990 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00001991 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00001992}
1993
reed@google.com9987ec32011-09-07 11:57:52 +00001994void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1995 const SkIRect& center, const SkRect& dst,
1996 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001997 if (bitmap.drawsNothing()) {
1998 return;
1999 }
reed@google.com3d608122011-11-21 15:16:16 +00002000 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00002001 SkRect storage;
2002 const SkRect* bounds = &dst;
2003 if (paint) {
2004 bounds = &paint->computeFastBounds(dst, &storage);
2005 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002006 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002007 return;
2008 }
2009 }
2010
reed@google.com9987ec32011-09-07 11:57:52 +00002011 const int32_t w = bitmap.width();
2012 const int32_t h = bitmap.height();
2013
2014 SkIRect c = center;
2015 // pin center to the bounds of the bitmap
2016 c.fLeft = SkMax32(0, center.fLeft);
2017 c.fTop = SkMax32(0, center.fTop);
2018 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2019 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2020
reed@google.com71121732012-09-18 15:14:33 +00002021 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002022 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00002023 };
2024 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002025 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00002026 };
reed@google.com9987ec32011-09-07 11:57:52 +00002027 SkScalar dstX[4] = {
2028 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2029 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2030 };
2031 SkScalar dstY[4] = {
2032 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2033 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2034 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002035
reed@google.com9987ec32011-09-07 11:57:52 +00002036 if (dstX[1] > dstX[2]) {
2037 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2038 dstX[2] = dstX[1];
2039 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002040
reed@google.com9987ec32011-09-07 11:57:52 +00002041 if (dstY[1] > dstY[2]) {
2042 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2043 dstY[2] = dstY[1];
2044 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002045
reed@google.com9987ec32011-09-07 11:57:52 +00002046 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00002047 SkRect s, d;
2048
reed@google.com9987ec32011-09-07 11:57:52 +00002049 s.fTop = srcY[y];
2050 s.fBottom = srcY[y+1];
2051 d.fTop = dstY[y];
2052 d.fBottom = dstY[y+1];
2053 for (int x = 0; x < 3; x++) {
2054 s.fLeft = srcX[x];
2055 s.fRight = srcX[x+1];
2056 d.fLeft = dstX[x];
2057 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002058 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00002059 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00002060 }
2061 }
2062}
2063
reed41af9662015-01-05 07:49:08 -08002064void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2065 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002066 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002067 SkDEBUGCODE(bitmap.validate();)
2068
2069 // Need a device entry-point, so gpu can use a mesh
2070 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2071}
2072
reed@google.comf67e4cf2011-03-15 20:56:58 +00002073class SkDeviceFilteredPaint {
2074public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002075 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002076 uint32_t filteredFlags = device->filterTextFlags(paint);
2077 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002078 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002079 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002080 fPaint = newPaint;
2081 } else {
2082 fPaint = &paint;
2083 }
2084 }
2085
reed@google.comf67e4cf2011-03-15 20:56:58 +00002086 const SkPaint& paint() const { return *fPaint; }
2087
2088private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002089 const SkPaint* fPaint;
2090 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002091};
2092
bungeman@google.com52c748b2011-08-22 21:30:43 +00002093void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2094 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002095 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002096 draw.fDevice->drawRect(draw, r, paint);
2097 } else {
2098 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002099 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002100 draw.fDevice->drawRect(draw, r, p);
2101 }
2102}
2103
2104void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2105 const char text[], size_t byteLength,
2106 SkScalar x, SkScalar y) {
2107 SkASSERT(byteLength == 0 || text != NULL);
2108
2109 // nothing to draw
2110 if (text == NULL || byteLength == 0 ||
2111 draw.fClip->isEmpty() ||
2112 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2113 return;
2114 }
2115
2116 SkScalar width = 0;
2117 SkPoint start;
2118
2119 start.set(0, 0); // to avoid warning
2120 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2121 SkPaint::kStrikeThruText_Flag)) {
2122 width = paint.measureText(text, byteLength);
2123
2124 SkScalar offsetX = 0;
2125 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2126 offsetX = SkScalarHalf(width);
2127 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2128 offsetX = width;
2129 }
2130 start.set(x - offsetX, y);
2131 }
2132
2133 if (0 == width) {
2134 return;
2135 }
2136
2137 uint32_t flags = paint.getFlags();
2138
2139 if (flags & (SkPaint::kUnderlineText_Flag |
2140 SkPaint::kStrikeThruText_Flag)) {
2141 SkScalar textSize = paint.getTextSize();
2142 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2143 SkRect r;
2144
2145 r.fLeft = start.fX;
2146 r.fRight = start.fX + width;
2147
2148 if (flags & SkPaint::kUnderlineText_Flag) {
2149 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2150 start.fY);
2151 r.fTop = offset;
2152 r.fBottom = offset + height;
2153 DrawRect(draw, paint, r, textSize);
2154 }
2155 if (flags & SkPaint::kStrikeThruText_Flag) {
2156 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2157 start.fY);
2158 r.fTop = offset;
2159 r.fBottom = offset + height;
2160 DrawRect(draw, paint, r, textSize);
2161 }
2162 }
2163}
2164
reed@google.come0d9ce82014-04-23 04:00:17 +00002165void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2166 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002167 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002168
2169 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002170 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002171 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002172 DrawTextDecorations(iter, dfp.paint(),
2173 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002174 }
2175
reed@google.com4e2b3d32011-04-07 14:18:59 +00002176 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002177}
2178
reed@google.come0d9ce82014-04-23 04:00:17 +00002179void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2180 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002181 SkPoint textOffset = SkPoint::Make(0, 0);
2182
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002183 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002184
reed@android.com8a1c16f2008-12-17 15:59:43 +00002185 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002186 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002187 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002188 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002189 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002190
reed@google.com4e2b3d32011-04-07 14:18:59 +00002191 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002192}
2193
reed@google.come0d9ce82014-04-23 04:00:17 +00002194void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2195 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002196
2197 SkPoint textOffset = SkPoint::Make(0, constY);
2198
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002199 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002200
reed@android.com8a1c16f2008-12-17 15:59:43 +00002201 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002202 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002203 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002204 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002205 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002206
reed@google.com4e2b3d32011-04-07 14:18:59 +00002207 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002208}
2209
reed@google.come0d9ce82014-04-23 04:00:17 +00002210void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2211 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002212 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002213
reed@android.com8a1c16f2008-12-17 15:59:43 +00002214 while (iter.next()) {
2215 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002216 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002217 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002218
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002219 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002220}
2221
fmalita00d5c2c2014-08-21 08:53:26 -07002222void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2223 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002224
fmalita85d5eb92015-03-04 11:20:12 -08002225 SkRect storage;
2226 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002227 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002228 storage = blob->bounds().makeOffset(x, y);
2229 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002230
fmalita85d5eb92015-03-04 11:20:12 -08002231 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002232 return;
2233 }
2234 }
2235
fmalita024f9962015-03-03 19:08:17 -08002236 // We cannot filter in the looper as we normally do, because the paint is
2237 // incomplete at this point (text-related attributes are embedded within blob run paints).
2238 SkDrawFilter* drawFilter = fMCRec->fFilter;
2239 fMCRec->fFilter = NULL;
2240
fmalita85d5eb92015-03-04 11:20:12 -08002241 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002242
fmalitaaa1b9122014-08-28 14:32:24 -07002243 while (iter.next()) {
2244 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002245 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002246 }
2247
fmalitaaa1b9122014-08-28 14:32:24 -07002248 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002249
2250 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002251}
2252
reed@google.come0d9ce82014-04-23 04:00:17 +00002253// These will become non-virtual, so they always call the (virtual) onDraw... method
2254void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2255 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002256 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002257 this->onDrawText(text, byteLength, x, y, paint);
2258}
2259void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2260 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002261 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002262 this->onDrawPosText(text, byteLength, pos, paint);
2263}
2264void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2265 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002266 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002267 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2268}
2269void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2270 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002271 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002272 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2273}
fmalita00d5c2c2014-08-21 08:53:26 -07002274void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2275 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002276 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002277 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002278 this->onDrawTextBlob(blob, x, y, paint);
2279 }
2280}
reed@google.come0d9ce82014-04-23 04:00:17 +00002281
reed41af9662015-01-05 07:49:08 -08002282void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2283 const SkPoint verts[], const SkPoint texs[],
2284 const SkColor colors[], SkXfermode* xmode,
2285 const uint16_t indices[], int indexCount,
2286 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002287 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002288 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002289
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290 while (iter.next()) {
2291 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002292 colors, xmode, indices, indexCount,
2293 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002294 }
reed@google.com4b226022011-01-11 18:32:13 +00002295
reed@google.com4e2b3d32011-04-07 14:18:59 +00002296 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002297}
2298
dandovb3c9d1c2014-08-12 08:34:29 -07002299void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2300 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002301 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002302 if (NULL == cubics) {
2303 return;
2304 }
mtklein6cfa73a2014-08-13 13:33:49 -07002305
dandovecfff212014-08-04 10:02:00 -07002306 // Since a patch is always within the convex hull of the control points, we discard it when its
2307 // bounding rectangle is completely outside the current clip.
2308 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002309 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002310 if (this->quickReject(bounds)) {
2311 return;
2312 }
mtklein6cfa73a2014-08-13 13:33:49 -07002313
dandovb3c9d1c2014-08-12 08:34:29 -07002314 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2315}
2316
2317void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2318 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2319
dandovecfff212014-08-04 10:02:00 -07002320 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002321
dandovecfff212014-08-04 10:02:00 -07002322 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002323 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002324 }
mtklein6cfa73a2014-08-13 13:33:49 -07002325
dandovecfff212014-08-04 10:02:00 -07002326 LOOPER_END
2327}
2328
reed3cb38402015-02-06 08:36:15 -08002329void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002330 if (dr && !this->quickReject(dr->getBounds())) {
2331 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002332 }
2333}
2334
reed3cb38402015-02-06 08:36:15 -08002335void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002336 dr->draw(this);
2337}
2338
reed@android.com8a1c16f2008-12-17 15:59:43 +00002339//////////////////////////////////////////////////////////////////////////////
2340// These methods are NOT virtual, and therefore must call back into virtual
2341// methods, rather than actually drawing themselves.
2342//////////////////////////////////////////////////////////////////////////////
2343
2344void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002345 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002346 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002347 SkPaint paint;
2348
2349 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002350 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002351 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002352 }
2353 this->drawPaint(paint);
2354}
2355
reed@android.com845fdac2009-06-23 03:01:32 +00002356void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002357 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002358 SkPaint paint;
2359
2360 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002361 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002362 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002363 }
2364 this->drawPaint(paint);
2365}
2366
2367void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002368 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002369 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002370
reed@android.com8a1c16f2008-12-17 15:59:43 +00002371 pt.set(x, y);
2372 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2373}
2374
2375void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002376 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002377 SkPoint pt;
2378 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002379
reed@android.com8a1c16f2008-12-17 15:59:43 +00002380 pt.set(x, y);
2381 paint.setColor(color);
2382 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2383}
2384
2385void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2386 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002387 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002388 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002389
reed@android.com8a1c16f2008-12-17 15:59:43 +00002390 pts[0].set(x0, y0);
2391 pts[1].set(x1, y1);
2392 this->drawPoints(kLines_PointMode, 2, pts, paint);
2393}
2394
2395void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2396 SkScalar right, SkScalar bottom,
2397 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002398 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002399 SkRect r;
2400
2401 r.set(left, top, right, bottom);
2402 this->drawRect(r, paint);
2403}
2404
2405void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2406 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002407 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002408 if (radius < 0) {
2409 radius = 0;
2410 }
2411
2412 SkRect r;
2413 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002414 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002415}
2416
2417void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2418 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002419 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002420 if (rx > 0 && ry > 0) {
2421 if (paint.canComputeFastBounds()) {
2422 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002423 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002424 return;
2425 }
2426 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002427 SkRRect rrect;
2428 rrect.setRectXY(r, rx, ry);
2429 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002430 } else {
2431 this->drawRect(r, paint);
2432 }
2433}
2434
reed@android.com8a1c16f2008-12-17 15:59:43 +00002435void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2436 SkScalar sweepAngle, bool useCenter,
2437 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002438 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002439 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2440 this->drawOval(oval, paint);
2441 } else {
2442 SkPath path;
2443 if (useCenter) {
2444 path.moveTo(oval.centerX(), oval.centerY());
2445 }
2446 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2447 if (useCenter) {
2448 path.close();
2449 }
2450 this->drawPath(path, paint);
2451 }
2452}
2453
2454void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2455 const SkPath& path, SkScalar hOffset,
2456 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002457 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002458 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002459
reed@android.com8a1c16f2008-12-17 15:59:43 +00002460 matrix.setTranslate(hOffset, vOffset);
2461 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2462}
2463
reed@android.comf76bacf2009-05-13 14:00:33 +00002464///////////////////////////////////////////////////////////////////////////////
robertphillips9b14f262014-06-04 05:40:44 -07002465void SkCanvas::drawPicture(const SkPicture* picture) {
danakj9881d632014-11-26 12:41:06 -08002466 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002467 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002468 this->onDrawPicture(picture, NULL, NULL);
robertphillips9b14f262014-06-04 05:40:44 -07002469 }
2470}
2471
reedd5fa1a42014-08-09 11:08:05 -07002472void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002473 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture(SkMatrix, SkPaint)");
bsalomon49f085d2014-09-05 13:34:00 -07002474 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002475 if (matrix && matrix->isIdentity()) {
2476 matrix = NULL;
2477 }
2478 this->onDrawPicture(picture, matrix, paint);
2479 }
2480}
robertphillips9b14f262014-06-04 05:40:44 -07002481
reedd5fa1a42014-08-09 11:08:05 -07002482void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2483 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002484 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002485 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002486 // Canvas has to first give the device the opportunity to render
2487 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002488 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002489 return; // the device has rendered the entire picture
2490 }
2491 }
2492
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002493 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
reedd5fa1a42014-08-09 11:08:05 -07002494
robertphillipsc5ba71d2014-09-04 08:42:50 -07002495 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496}
2497
reed@android.com8a1c16f2008-12-17 15:59:43 +00002498///////////////////////////////////////////////////////////////////////////////
2499///////////////////////////////////////////////////////////////////////////////
2500
2501SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002502 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002503
2504 SkASSERT(canvas);
2505
2506 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2507 fDone = !fImpl->next();
2508}
2509
2510SkCanvas::LayerIter::~LayerIter() {
2511 fImpl->~SkDrawIter();
2512}
2513
2514void SkCanvas::LayerIter::next() {
2515 fDone = !fImpl->next();
2516}
2517
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002518SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002519 return fImpl->getDevice();
2520}
2521
2522const SkMatrix& SkCanvas::LayerIter::matrix() const {
2523 return fImpl->getMatrix();
2524}
2525
2526const SkPaint& SkCanvas::LayerIter::paint() const {
2527 const SkPaint* paint = fImpl->getPaint();
2528 if (NULL == paint) {
2529 paint = &fDefaultPaint;
2530 }
2531 return *paint;
2532}
2533
2534const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2535int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2536int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002537
2538///////////////////////////////////////////////////////////////////////////////
2539
fmalitac3b589a2014-06-05 12:40:07 -07002540SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002541
2542///////////////////////////////////////////////////////////////////////////////
2543
2544static bool supported_for_raster_canvas(const SkImageInfo& info) {
2545 switch (info.alphaType()) {
2546 case kPremul_SkAlphaType:
2547 case kOpaque_SkAlphaType:
2548 break;
2549 default:
2550 return false;
2551 }
2552
2553 switch (info.colorType()) {
2554 case kAlpha_8_SkColorType:
2555 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002556 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002557 break;
2558 default:
2559 return false;
2560 }
2561
2562 return true;
2563}
2564
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002565SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2566 if (!supported_for_raster_canvas(info)) {
2567 return NULL;
2568 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002569
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002570 SkBitmap bitmap;
2571 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2572 return NULL;
2573 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002574 return SkNEW_ARGS(SkCanvas, (bitmap));
2575}
reedd5fa1a42014-08-09 11:08:05 -07002576
2577///////////////////////////////////////////////////////////////////////////////
2578
2579SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002580 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002581 : fCanvas(canvas)
2582 , fSaveCount(canvas->getSaveCount())
2583{
bsalomon49f085d2014-09-05 13:34:00 -07002584 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002585 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002586 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002587 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002588 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002589 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002590 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002591 canvas->save();
2592 }
mtklein6cfa73a2014-08-13 13:33:49 -07002593
bsalomon49f085d2014-09-05 13:34:00 -07002594 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002595 canvas->concat(*matrix);
2596 }
2597}
2598
2599SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2600 fCanvas->restoreToCount(fSaveCount);
2601}