blob: 6169492a765b4439dcce1ac000ec05062dc9db94 [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"
reeddbc3cef2015-04-29 12:18:57 -070011#include "SkColorFilter.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,
reed86a17e72015-05-14 12:25:22 -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;
reed41e010c2015-06-09 12:16:53 -0700272 if (!fDevice->accessPixels(&fDst)) {
273 fDst.reset(fDevice->imageInfo(), NULL, 0);
274 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000276 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277
278 fCurrLayer = rec->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 // fCurrLayer may be NULL now
reed@android.com199f1082009-06-10 02:12:47 +0000280
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 return true;
282 }
283 return false;
284 }
reed@google.com4b226022011-01-11 18:32:13 +0000285
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000286 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000287 int getX() const { return fDevice->getOrigin().x(); }
288 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289 const SkMatrix& getMatrix() const { return *fMatrix; }
290 const SkRegion& getClip() const { return *fClip; }
291 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000292
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293private:
294 SkCanvas* fCanvas;
295 const DeviceCM* fCurrLayer;
296 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 SkBool8 fSkipEmptyClips;
298
299 typedef SkDraw INHERITED;
300};
301
302/////////////////////////////////////////////////////////////////////////////
303
reeddbc3cef2015-04-29 12:18:57 -0700304static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
305 return lazy->isValid() ? lazy->get() : lazy->set(orig);
306}
307
308/**
309 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
310 * colorfilter, else return NULL.
311 */
312static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700313 SkImageFilter* imgf = paint.getImageFilter();
314 if (!imgf) {
315 return NULL;
316 }
317
318 SkColorFilter* imgCF;
319 if (!imgf->asAColorFilter(&imgCF)) {
320 return NULL;
321 }
322
323 SkColorFilter* paintCF = paint.getColorFilter();
324 if (NULL == paintCF) {
325 // there is no existing paint colorfilter, so we can just return the imagefilter's
326 return imgCF;
327 }
328
329 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
330 // and we need to combine them into a single colorfilter.
331 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
332 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
reeddbc3cef2015-04-29 12:18:57 -0700333}
334
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335class AutoDrawLooper {
336public:
reed4a8126e2014-09-22 07:29:03 -0700337 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000338 bool skipLayerForImageFilter = false,
339 const SkRect* bounds = NULL) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000340 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700342 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000343 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700344 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000345 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346
reeddbc3cef2015-04-29 12:18:57 -0700347 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
348 if (simplifiedCF) {
349 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
350 paint->setColorFilter(simplifiedCF)->unref();
351 paint->setImageFilter(NULL);
352 fPaint = paint;
353 }
354
355 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700356 /**
357 * We implement ImageFilters for a given draw by creating a layer, then applying the
358 * imagefilter to the pixels of that layer (its backing surface/image), and then
359 * we call restore() to xfer that layer to the main canvas.
360 *
361 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
362 * 2. Generate the src pixels:
363 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
364 * return (fPaint). We then draw the primitive (using srcover) into a cleared
365 * buffer/surface.
366 * 3. Restore the layer created in #1
367 * The imagefilter is passed the buffer/surface from the layer (now filled with the
368 * src pixels of the primitive). It returns a new "filtered" buffer, which we
369 * draw onto the previous layer using the xfermode from the original paint.
370 */
reed@google.com8926b162012-03-23 15:36:36 +0000371 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700372 tmp.setImageFilter(fPaint->getImageFilter());
373 tmp.setXfermode(fPaint->getXfermode());
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000374 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
reed76033be2015-03-14 10:54:31 -0700375 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700376 fTempLayerForImageFilter = true;
377 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000378 }
379
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000380 if (SkDrawLooper* looper = paint.getLooper()) {
381 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
382 looper->contextSize());
383 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000384 fIsSimple = false;
385 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000386 fLooperContext = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000387 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700388 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000389 }
piotaixrb5fae932014-09-24 13:03:30 -0700390
reed4a8126e2014-09-22 07:29:03 -0700391 uint32_t oldFlags = paint.getFlags();
392 fNewPaintFlags = filter_paint_flags(props, oldFlags);
393 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700394 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700395 paint->setFlags(fNewPaintFlags);
396 fPaint = paint;
397 // if we're not simple, doNext() will take care of calling setFlags()
398 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000399 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000400
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700402 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000403 fCanvas->internalRestore();
404 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000405 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000406 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000407
reed@google.com4e2b3d32011-04-07 14:18:59 +0000408 const SkPaint& paint() const {
409 SkASSERT(fPaint);
410 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000411 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000412
reed@google.com129ec222012-05-15 13:24:09 +0000413 bool next(SkDrawFilter::Type drawType) {
414 if (fDone) {
415 return false;
416 } else if (fIsSimple) {
417 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000418 return !fPaint->nothingToDraw();
419 } else {
420 return this->doNext(drawType);
421 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000422 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000423
reed@android.com8a1c16f2008-12-17 15:59:43 +0000424private:
reeddbc3cef2015-04-29 12:18:57 -0700425 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
426 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000427 SkCanvas* fCanvas;
428 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000429 SkDrawFilter* fFilter;
430 const SkPaint* fPaint;
431 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700432 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700433 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000434 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000435 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000436 SkDrawLooper::Context* fLooperContext;
437 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000438
439 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440};
441
reed@google.com129ec222012-05-15 13:24:09 +0000442bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
reed@google.com632e1a22011-10-06 12:37:00 +0000443 fPaint = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000444 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700445 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000446
reeddbc3cef2015-04-29 12:18:57 -0700447 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
448 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700449 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000450
reed5c476fb2015-04-20 08:04:21 -0700451 if (fTempLayerForImageFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000452 paint->setImageFilter(NULL);
reed5c476fb2015-04-20 08:04:21 -0700453 paint->setXfermode(NULL);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000454 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000455
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000456 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000457 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000458 return false;
459 }
460 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000461 if (!fFilter->filter(paint, drawType)) {
462 fDone = true;
463 return false;
464 }
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000465 if (NULL == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000466 // no looper means we only draw once
467 fDone = true;
468 }
469 }
470 fPaint = paint;
471
472 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000473 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000474 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000475 }
476
477 // call this after any possible paint modifiers
478 if (fPaint->nothingToDraw()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000479 fPaint = NULL;
480 return false;
481 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000482 return true;
483}
484
reed@android.com8a1c16f2008-12-17 15:59:43 +0000485////////// macros to place around the internal draw calls //////////////////
486
reed@google.com8926b162012-03-23 15:36:36 +0000487#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000488 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700489 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000490 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000491 SkDrawIter iter(this);
492
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000493#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000494 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700495 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000496 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000498
reed@google.com4e2b3d32011-04-07 14:18:59 +0000499#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000500
501////////////////////////////////////////////////////////////////////////////
502
mtkleinfeaadee2015-04-08 11:25:48 -0700503void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
504 this->restoreToCount(1);
505 fCachedLocalClipBounds.setEmpty();
506 fCachedLocalClipBoundsDirty = true;
507 fClipStack->reset();
508 fMCRec->reset(bounds);
509
510 // We're peering through a lot of structs here. Only at this scope do we
511 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
512 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
513}
514
reedd9544982014-09-09 18:46:22 -0700515SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
516 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
reed@google.comc0784db2013-12-13 21:16:12 +0000517 fCachedLocalClipBounds.setEmpty();
518 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000519 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000520 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700521 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800522 fSaveCount = 1;
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000523 fMetaData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000524
reed687fa1c2015-04-07 08:00:56 -0700525 fClipStack.reset(SkNEW(SkClipStack));
526
reed@android.com8a1c16f2008-12-17 15:59:43 +0000527 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700528 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000529
reeda499f902015-05-01 09:34:31 -0700530 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
531 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed86a17e72015-05-14 12:25:22 -0700532 new (fDeviceCMStorage) DeviceCM(NULL, NULL, NULL, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700533
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000535
reed@google.com97af1a62012-08-28 12:19:02 +0000536 fSurfaceBase = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000537
reedf92c8662014-08-18 08:02:43 -0700538 if (device) {
robertphillipsfcf78292015-06-19 11:49:52 -0700539 // TODO: remove this - the root device & canvas should always have same surfaceProps
reedb2db8982014-11-13 12:41:02 -0800540 device->initForRootLayer(fProps.pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700541 if (device->forceConservativeRasterClip()) {
542 fConservativeRasterClip = true;
543 }
reedf92c8662014-08-18 08:02:43 -0700544 device->onAttachToCanvas(this);
545 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800546 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700547 }
548 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549}
550
reed@google.comcde92112011-07-06 20:00:52 +0000551SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000552 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700553 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000554{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000555 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000556
reedd9544982014-09-09 18:46:22 -0700557 this->init(NULL, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000558}
559
reedd9544982014-09-09 18:46:22 -0700560static SkBitmap make_nopixels(int width, int height) {
561 SkBitmap bitmap;
562 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
563 return bitmap;
564}
565
566class SkNoPixelsBitmapDevice : public SkBitmapDevice {
567public:
robertphillipsfcf78292015-06-19 11:49:52 -0700568 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
569 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800570 {
571 this->setOrigin(bounds.x(), bounds.y());
572 }
reedd9544982014-09-09 18:46:22 -0700573
574private:
piotaixrb5fae932014-09-24 13:03:30 -0700575
reedd9544982014-09-09 18:46:22 -0700576 typedef SkBitmapDevice INHERITED;
577};
578
reed96a857e2015-01-25 10:33:58 -0800579SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000580 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800581 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000582{
583 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700584
reed78e27682014-11-19 08:04:34 -0800585 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
robertphillipsfcf78292015-06-19 11:49:52 -0700586 (SkIRect::MakeWH(width, height), fProps)), kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700587}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000588
reed78e27682014-11-19 08:04:34 -0800589SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700590 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700591 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700592{
593 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700594
robertphillipsfcf78292015-06-19 11:49:52 -0700595 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds, fProps)), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700596}
597
robertphillipsfcf78292015-06-19 11:49:52 -0700598// TODO: remove this ctor
reed4a8126e2014-09-22 07:29:03 -0700599SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700600 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700601 , fProps(SkSurfacePropsCopyOrDefault(props))
reedd9544982014-09-09 18:46:22 -0700602{
603 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700604
reedd9544982014-09-09 18:46:22 -0700605 this->init(device, flags);
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000606}
607
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000608SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000609 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700610 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000611{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700613
reedd9544982014-09-09 18:46:22 -0700614 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615}
616
robertphillipsfcf78292015-06-19 11:49:52 -0700617SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
618 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700619 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700620{
621 inc_canvas();
622
623 this->init(device, flags);
624}
625
reed4a8126e2014-09-22 07:29:03 -0700626SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700627 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700628 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700629{
630 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700631
robertphillipsfcf78292015-06-19 11:49:52 -0700632 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap, fProps)));
reed4a8126e2014-09-22 07:29:03 -0700633 this->init(device, kDefault_InitFlags);
634}
reed29c857d2014-09-21 10:25:07 -0700635
reed4a8126e2014-09-22 07:29:03 -0700636SkCanvas::SkCanvas(const SkBitmap& bitmap)
637 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
638 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
639{
640 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700641
robertphillipsfcf78292015-06-19 11:49:52 -0700642 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap, fProps)));
reed4a8126e2014-09-22 07:29:03 -0700643 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644}
645
646SkCanvas::~SkCanvas() {
647 // free up the contents of our deque
648 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000649
reed@android.com8a1c16f2008-12-17 15:59:43 +0000650 this->internalRestore(); // restore the last, since we're going away
651
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000652 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000653
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654 dec_canvas();
655}
656
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657SkDrawFilter* SkCanvas::getDrawFilter() const {
658 return fMCRec->fFilter;
659}
660
661SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700662 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
664 return filter;
665}
666
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000667SkMetaData& SkCanvas::getMetaData() {
668 // metadata users are rare, so we lazily allocate it. If that changes we
669 // can decide to just make it a field in the device (rather than a ptr)
670 if (NULL == fMetaData) {
671 fMetaData = new SkMetaData;
672 }
673 return *fMetaData;
674}
675
reed@android.com8a1c16f2008-12-17 15:59:43 +0000676///////////////////////////////////////////////////////////////////////////////
677
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000678void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000679 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000680 if (device) {
681 device->flush();
682 }
683}
684
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000685SkISize SkCanvas::getTopLayerSize() const {
686 SkBaseDevice* d = this->getTopDevice();
687 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
688}
689
690SkIPoint SkCanvas::getTopLayerOrigin() const {
691 SkBaseDevice* d = this->getTopDevice();
692 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
693}
694
695SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000696 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000697 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
698}
699
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000700SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000701 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000702 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000703 SkASSERT(rec && rec->fLayer);
704 return rec->fLayer->fDevice;
705}
706
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000707SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000708 if (updateMatrixClip) {
709 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
710 }
reed@google.com9266fed2011-03-30 00:18:03 +0000711 return fMCRec->fTopLayer->fDevice;
712}
713
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000714bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
715 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
716 return false;
717 }
718
719 bool weAllocated = false;
720 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700721 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000722 return false;
723 }
724 weAllocated = true;
725 }
726
reedcf01e312015-05-23 19:14:51 -0700727 SkAutoPixmapUnlock unlocker;
728 if (bitmap->requestLock(&unlocker)) {
729 const SkPixmap& pm = unlocker.pixmap();
730 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
731 return true;
732 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000733 }
734
735 if (weAllocated) {
736 bitmap->setPixelRef(NULL);
737 }
738 return false;
739}
reed@google.com51df9e32010-12-23 19:29:18 +0000740
bsalomon@google.comc6980972011-11-02 19:57:21 +0000741bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000742 SkIRect r = srcRect;
743 const SkISize size = this->getBaseLayerSize();
744 if (!r.intersect(0, 0, size.width(), size.height())) {
745 bitmap->reset();
746 return false;
747 }
748
reed84825042014-09-02 12:50:45 -0700749 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000750 // bitmap will already be reset.
751 return false;
752 }
753 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
754 bitmap->reset();
755 return false;
756 }
757 return true;
758}
759
reed96472de2014-12-10 09:53:42 -0800760bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000761 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000762 if (!device) {
763 return false;
764 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000765 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800766
reed96472de2014-12-10 09:53:42 -0800767 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
768 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000769 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000770 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000771
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000772 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800773 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000774}
775
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000776bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
777 if (bitmap.getTexture()) {
778 return false;
779 }
reedcf01e312015-05-23 19:14:51 -0700780
781 SkAutoPixmapUnlock unlocker;
782 if (bitmap.requestLock(&unlocker)) {
783 const SkPixmap& pm = unlocker.pixmap();
784 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000785 }
786 return false;
787}
788
789bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
790 int x, int y) {
791 switch (origInfo.colorType()) {
792 case kUnknown_SkColorType:
793 case kIndex_8_SkColorType:
794 return false;
795 default:
796 break;
797 }
798 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
799 return false;
800 }
801
802 const SkISize size = this->getBaseLayerSize();
803 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
804 if (!target.intersect(0, 0, size.width(), size.height())) {
805 return false;
806 }
807
808 SkBaseDevice* device = this->getDevice();
809 if (!device) {
810 return false;
811 }
812
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000813 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700814 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000815
816 // if x or y are negative, then we have to adjust pixels
817 if (x > 0) {
818 x = 0;
819 }
820 if (y > 0) {
821 y = 0;
822 }
823 // here x,y are either 0 or negative
824 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
825
reed4af35f32014-06-27 17:47:49 -0700826 // Tell our owning surface to bump its generation ID
827 this->predrawNotify();
828
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000829 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000830 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000831}
reed@google.com51df9e32010-12-23 19:29:18 +0000832
junov@google.com4370aed2012-01-18 16:21:08 +0000833SkCanvas* SkCanvas::canvasForDrawIter() {
834 return this;
835}
836
reed@android.com8a1c16f2008-12-17 15:59:43 +0000837//////////////////////////////////////////////////////////////////////////////
838
reed@android.com8a1c16f2008-12-17 15:59:43 +0000839void SkCanvas::updateDeviceCMCache() {
840 if (fDeviceCMDirty) {
841 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700842 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000843 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000844
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845 if (NULL == layer->fNext) { // only one layer
reed687fa1c2015-04-07 08:00:56 -0700846 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000847 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000848 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000849 do {
reed687fa1c2015-04-07 08:00:56 -0700850 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851 } while ((layer = layer->fNext) != NULL);
852 }
853 fDeviceCMDirty = false;
854 }
855}
856
reed@android.com8a1c16f2008-12-17 15:59:43 +0000857///////////////////////////////////////////////////////////////////////////////
858
reed2ff1fce2014-12-11 07:07:37 -0800859void SkCanvas::checkForDeferredSave() {
860 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800861 this->doSave();
862 }
863}
864
reedf0090cb2014-11-26 08:55:51 -0800865int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800866#ifdef SK_DEBUG
867 int count = 0;
868 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
869 for (;;) {
870 const MCRec* rec = (const MCRec*)iter.next();
871 if (!rec) {
872 break;
873 }
874 count += 1 + rec->fDeferredSaveCount;
875 }
876 SkASSERT(count == fSaveCount);
877#endif
878 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800879}
880
881int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800882 fSaveCount += 1;
883 fMCRec->fDeferredSaveCount += 1;
884 return this->getSaveCount() - 1; // return our prev value
885}
886
887void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800888 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700889
890 SkASSERT(fMCRec->fDeferredSaveCount > 0);
891 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800892 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800893}
894
895void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800896 if (fMCRec->fDeferredSaveCount > 0) {
897 SkASSERT(fSaveCount > 1);
898 fSaveCount -= 1;
899 fMCRec->fDeferredSaveCount -= 1;
900 } else {
901 // check for underflow
902 if (fMCStack.count() > 1) {
903 this->willRestore();
904 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700905 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800906 this->internalRestore();
907 this->didRestore();
908 }
reedf0090cb2014-11-26 08:55:51 -0800909 }
910}
911
912void SkCanvas::restoreToCount(int count) {
913 // sanity check
914 if (count < 1) {
915 count = 1;
916 }
mtkleinf0f14112014-12-12 08:46:25 -0800917
reedf0090cb2014-11-26 08:55:51 -0800918 int n = this->getSaveCount() - count;
919 for (int i = 0; i < n; ++i) {
920 this->restore();
921 }
922}
923
reed2ff1fce2014-12-11 07:07:37 -0800924void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000925 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700926 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000927 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000928
reed687fa1c2015-04-07 08:00:56 -0700929 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000930}
931
reed@android.com8a1c16f2008-12-17 15:59:43 +0000932static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000933#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000934 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000935#else
936 return true;
937#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000938}
939
junov@chromium.orga907ac32012-02-24 21:54:07 +0000940bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700941 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000942 SkIRect clipBounds;
943 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000944 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000945 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000946
reed96e657d2015-03-10 17:30:07 -0700947 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
948
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000949 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700950 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000951 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000952 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700953 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000954 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000955
reed96e657d2015-03-10 17:30:07 -0700956 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000957 r.roundOut(&ir);
958 // early exit if the layer's bounds are clipped out
959 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000960 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700961 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700962 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000963 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000964 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965 }
966 } else { // no user bounds, so just use the clip
967 ir = clipBounds;
968 }
reed180aec42015-03-11 10:39:04 -0700969 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000971 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -0700972 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -0700973 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -0700974 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -0700975 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000976 }
977
978 if (intersection) {
979 *intersection = ir;
980 }
981 return true;
982}
983
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000984int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800985 if (gIgnoreSaveLayerBounds) {
986 bounds = NULL;
987 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000988 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -0700989 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700990 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800991 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000992}
993
reed2ff1fce2014-12-11 07:07:37 -0800994int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800995 if (gIgnoreSaveLayerBounds) {
996 bounds = NULL;
997 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000998 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -0700999 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -07001000 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -08001001 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +00001002}
1003
reed2ff1fce2014-12-11 07:07:37 -08001004void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -07001005 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +00001006#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +00001007 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +00001008#endif
1009
junov@chromium.orga907ac32012-02-24 21:54:07 +00001010 // do this before we create the layer. We don't call the public save() since
1011 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001012 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001013
1014 fDeviceCMDirty = true;
1015
1016 SkIRect ir;
reeddaa57bf2015-05-15 10:39:17 -07001017 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -08001018 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001019 }
1020
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001021 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1022 // the clipRectBounds() call above?
1023 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001024 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001025 }
1026
reed76033be2015-03-14 10:54:31 -07001027 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001028 SkPixelGeometry geo = fProps.pixelGeometry();
1029 if (paint) {
reed76033be2015-03-14 10:54:31 -07001030 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001031 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001032 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001033 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001034 }
1035 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001036 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1037 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001038
reedb2db8982014-11-13 12:41:02 -08001039 SkBaseDevice* device = this->getTopDevice();
1040 if (NULL == device) {
1041 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001042 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001043 }
reedb2db8982014-11-13 12:41:02 -08001044
reed61f501f2015-04-29 08:34:00 -07001045 bool forceSpriteOnRestore = false;
1046 {
reeddaa57bf2015-05-15 10:39:17 -07001047 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed61f501f2015-04-29 08:34:00 -07001048 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo);
1049 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
1050 if (NULL == newDev) {
1051 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillipsfcf78292015-06-19 11:49:52 -07001052 const SkSurfaceProps surfaceProps(0, createInfo.fPixelGeometry);
1053 newDev = SkBitmapDevice::Create(createInfo.fInfo, &surfaceProps);
reed61f501f2015-04-29 08:34:00 -07001054 if (NULL == newDev) {
1055 SkErrorInternals::SetError(kInternalError_SkError,
1056 "Unable to create device for layer.");
1057 return;
1058 }
1059 forceSpriteOnRestore = true;
1060 }
1061 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001062 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001063
reed@google.com6f8f2922011-03-04 22:27:10 +00001064 device->setOrigin(ir.fLeft, ir.fTop);
reed61f501f2015-04-29 08:34:00 -07001065 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip,
reed86a17e72015-05-14 12:25:22 -07001066 forceSpriteOnRestore));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001067 device->unref();
1068
1069 layer->fNext = fMCRec->fTopLayer;
1070 fMCRec->fLayer = layer;
1071 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072}
1073
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001074int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1075 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1076}
1077
reed@android.com8a1c16f2008-12-17 15:59:43 +00001078int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1079 SaveFlags flags) {
1080 if (0xFF == alpha) {
1081 return this->saveLayer(bounds, NULL, flags);
1082 } else {
1083 SkPaint tmpPaint;
1084 tmpPaint.setAlpha(alpha);
1085 return this->saveLayer(bounds, &tmpPaint, flags);
1086 }
1087}
1088
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089void SkCanvas::internalRestore() {
1090 SkASSERT(fMCStack.count() != 0);
1091
1092 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001093 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001094
reed687fa1c2015-04-07 08:00:56 -07001095 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001096
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001097 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001098 DeviceCM* layer = fMCRec->fLayer; // may be null
1099 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1100 fMCRec->fLayer = NULL;
1101
1102 // now do the normal restore()
1103 fMCRec->~MCRec(); // balanced in save()
1104 fMCStack.pop_back();
1105 fMCRec = (MCRec*)fMCStack.back();
1106
1107 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1108 since if we're being recorded, we don't want to record this (the
1109 recorder will have already recorded the restore).
1110 */
bsalomon49f085d2014-09-05 13:34:00 -07001111 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001112 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001113 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001114 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001115 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001116 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001117 fDeviceCMDirty = true;
reedb679ca82015-04-07 04:40:48 -07001118 SkDELETE(layer);
1119 } else {
1120 // we're at the root
reeda499f902015-05-01 09:34:31 -07001121 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001122 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001123 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001124 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001125}
1126
reed4a8126e2014-09-22 07:29:03 -07001127SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1128 if (NULL == props) {
1129 props = &fProps;
1130 }
1131 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001132}
1133
reed4a8126e2014-09-22 07:29:03 -07001134SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001135 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001136 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001137}
1138
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001139SkImageInfo SkCanvas::imageInfo() const {
1140 SkBaseDevice* dev = this->getDevice();
1141 if (dev) {
1142 return dev->imageInfo();
1143 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001144 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001145 }
1146}
1147
1148const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001149 SkPixmap pmap;
1150 if (!this->onPeekPixels(&pmap)) {
1151 return NULL;
1152 }
1153 if (info) {
1154 *info = pmap.info();
1155 }
1156 if (rowBytes) {
1157 *rowBytes = pmap.rowBytes();
1158 }
1159 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001160}
1161
reed884e97c2015-05-26 11:31:54 -07001162bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001163 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001164 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001165}
1166
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001167void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001168 SkPixmap pmap;
1169 if (!this->onAccessTopLayerPixels(&pmap)) {
1170 return NULL;
1171 }
1172 if (info) {
1173 *info = pmap.info();
1174 }
1175 if (rowBytes) {
1176 *rowBytes = pmap.rowBytes();
1177 }
1178 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001179 *origin = this->getTopDevice(false)->getOrigin();
1180 }
reed884e97c2015-05-26 11:31:54 -07001181 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001182}
1183
reed884e97c2015-05-26 11:31:54 -07001184bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001185 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001186 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001187}
1188
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001189SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1190 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1191 if (NULL == fAddr) {
1192 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001193 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001194 return; // failure, fAddr is NULL
1195 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001196 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1197 return; // failure, fAddr is NULL
1198 }
1199 fAddr = fBitmap.getPixels();
1200 fRowBytes = fBitmap.rowBytes();
1201 }
1202 SkASSERT(fAddr); // success
1203}
1204
1205bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1206 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001207 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001208 } else {
1209 bitmap->reset();
1210 return false;
1211 }
1212}
1213
reed@android.com8a1c16f2008-12-17 15:59:43 +00001214/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001215void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001216 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001217 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218 return;
1219 }
1220
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001221 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001223 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001225
1226 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001227
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001228 SkRect storage;
1229 const SkRect* bounds = NULL;
1230 if (paint && paint->canComputeFastBounds()) {
1231 bitmap.getBounds(&storage);
1232 matrix.mapRect(&storage);
1233 bounds = &paint->computeFastBounds(storage, &storage);
1234 }
1235
1236 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001237
1238 while (iter.next()) {
1239 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1240 }
1241
1242 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001243}
1244
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001245void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001246 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247 SkPaint tmp;
1248 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001249 paint = &tmp;
1250 }
reed@google.com4b226022011-01-11 18:32:13 +00001251
reed@google.com8926b162012-03-23 15:36:36 +00001252 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001253 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001254 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001255 paint = &looper.paint();
1256 SkImageFilter* filter = paint->getImageFilter();
1257 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001258 if (filter && !dstDev->canHandleImageFilter(filter)) {
reed2c55d7b2015-06-09 08:18:39 -07001259 SkImageFilter::Proxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001260 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001261 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001262 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001263 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001264 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001265 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001266 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001267 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001268 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001269 SkPaint tmpUnfiltered(*paint);
1270 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001271 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1272 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001273 }
reed61f501f2015-04-29 08:34:00 -07001274 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001275 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001276 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001277 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001278 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001279 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001280 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001281 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001282}
1283
reed41af9662015-01-05 07:49:08 -08001284void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001285 if (gTreatSpriteAsBitmap) {
1286 this->save();
1287 this->resetMatrix();
1288 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1289 this->restore();
1290 return;
1291 }
1292
danakj9881d632014-11-26 12:41:06 -08001293 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001294 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001295 return;
1296 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001297 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001298
reed@google.com8926b162012-03-23 15:36:36 +00001299 SkPaint tmp;
1300 if (NULL == paint) {
1301 paint = &tmp;
1302 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001303
reed@google.com8926b162012-03-23 15:36:36 +00001304 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001305
reed@google.com8926b162012-03-23 15:36:36 +00001306 while (iter.next()) {
1307 paint = &looper.paint();
1308 SkImageFilter* filter = paint->getImageFilter();
1309 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1310 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
reed2c55d7b2015-06-09 08:18:39 -07001311 SkImageFilter::Proxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001312 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001313 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001314 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001315 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001316 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001317 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001318 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001319 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001320 SkPaint tmpUnfiltered(*paint);
1321 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001322 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001323 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001324 }
1325 } else {
1326 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1327 }
1328 }
1329 LOOPER_END
1330}
1331
reed@android.com8a1c16f2008-12-17 15:59:43 +00001332/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001333void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001334 SkMatrix m;
1335 m.setTranslate(dx, dy);
1336 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337}
1338
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001339void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001340 SkMatrix m;
1341 m.setScale(sx, sy);
1342 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343}
1344
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001345void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001346 SkMatrix m;
1347 m.setRotate(degrees);
1348 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001349}
1350
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001351void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001352 SkMatrix m;
1353 m.setSkew(sx, sy);
1354 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001355}
1356
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001357void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001358 if (matrix.isIdentity()) {
1359 return;
1360 }
1361
reed2ff1fce2014-12-11 07:07:37 -08001362 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001363 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001364 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001365 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001366
1367 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001368}
1369
reed86a17e72015-05-14 12:25:22 -07001370void SkCanvas::setMatrix(const SkMatrix& matrix) {
1371 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001372 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001373 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001374 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001375 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001376}
1377
reed@android.com8a1c16f2008-12-17 15:59:43 +00001378void SkCanvas::resetMatrix() {
1379 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001380
reed@android.com8a1c16f2008-12-17 15:59:43 +00001381 matrix.reset();
1382 this->setMatrix(matrix);
1383}
1384
1385//////////////////////////////////////////////////////////////////////////////
1386
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001387void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001388 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001389 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1390 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001391}
1392
1393void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001394#ifdef SK_ENABLE_CLIP_QUICKREJECT
1395 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001396 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001397 return false;
1398 }
1399
reed@google.com3b3e8952012-08-16 20:53:31 +00001400 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001401 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001402 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001403
reed687fa1c2015-04-07 08:00:56 -07001404 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001405 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001406 }
1407 }
1408#endif
1409
reed@google.com5c3d1472011-02-22 19:12:23 +00001410 AutoValidateClip avc(this);
1411
reed@android.com8a1c16f2008-12-17 15:59:43 +00001412 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001413 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001414 if (!fAllowSoftClip) {
1415 edgeStyle = kHard_ClipEdgeStyle;
1416 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001417
reed1f836ee2014-07-07 07:49:34 -07001418 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001419 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001420 // the matrix. This means we don't have to a) make a path, and b) tell
1421 // the region code to scan-convert the path, only to discover that it
1422 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424
reed1f836ee2014-07-07 07:49:34 -07001425 fMCRec->fMatrix.mapRect(&r, rect);
reed687fa1c2015-04-07 08:00:56 -07001426 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001427 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001429 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001430 // and clip against that, since it can handle any matrix. However, to
1431 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1432 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001433 SkPath path;
1434
1435 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001436 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001437 }
1438}
1439
reed73e714e2014-09-04 09:02:23 -07001440static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1441 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001442 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001443}
1444
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001445void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001446 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001447 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001448 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001449 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1450 } else {
1451 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001452 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001453}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001454
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001455void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001456 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001457 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001458 AutoValidateClip avc(this);
1459
1460 fDeviceCMDirty = true;
1461 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001462 if (!fAllowSoftClip) {
1463 edgeStyle = kHard_ClipEdgeStyle;
1464 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001465
reed687fa1c2015-04-07 08:00:56 -07001466 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001467
1468 SkPath devPath;
1469 devPath.addRRect(transformedRRect);
1470
reed73e714e2014-09-04 09:02:23 -07001471 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001472 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001473 }
1474
1475 SkPath path;
1476 path.addRRect(rrect);
1477 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001478 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001479}
1480
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001481void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001482 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001483 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1484 SkRect r;
1485 if (!path.isInverseFillType() && path.isRect(&r)) {
1486 this->onClipRect(r, op, edgeStyle);
1487 } else {
1488 this->onClipPath(path, op, edgeStyle);
1489 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001490}
1491
1492void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001493#ifdef SK_ENABLE_CLIP_QUICKREJECT
1494 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001495 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001496 return false;
1497 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001498
reed@google.com3b3e8952012-08-16 20:53:31 +00001499 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001500 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001501 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001502
reed687fa1c2015-04-07 08:00:56 -07001503 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001504 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001505 }
1506 }
1507#endif
1508
reed@google.com5c3d1472011-02-22 19:12:23 +00001509 AutoValidateClip avc(this);
1510
reed@android.com8a1c16f2008-12-17 15:59:43 +00001511 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001512 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001513 if (!fAllowSoftClip) {
1514 edgeStyle = kHard_ClipEdgeStyle;
1515 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001516
1517 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001518 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001519
reed@google.comfe701122011-11-08 19:41:23 +00001520 // Check if the transfomation, or the original path itself
1521 // made us empty. Note this can also happen if we contained NaN
1522 // values. computing the bounds detects this, and will set our
1523 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1524 if (devPath.getBounds().isEmpty()) {
1525 // resetting the path will remove any NaN or other wanky values
1526 // that might upset our scan converter.
1527 devPath.reset();
1528 }
1529
reed@google.com5c3d1472011-02-22 19:12:23 +00001530 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001531 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001532
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001533 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001534 bool clipIsAA = getClipStack()->asPath(&devPath);
1535 if (clipIsAA) {
1536 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001537 }
fmalita1a481fe2015-02-04 07:39:34 -08001538
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001539 op = SkRegion::kReplace_Op;
1540 }
1541
reed73e714e2014-09-04 09:02:23 -07001542 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001543}
1544
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001545void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001546 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001547 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001548}
1549
1550void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001551 AutoValidateClip avc(this);
1552
reed@android.com8a1c16f2008-12-17 15:59:43 +00001553 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001554 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001555
reed@google.com5c3d1472011-02-22 19:12:23 +00001556 // todo: signal fClipStack that we have a region, and therefore (I guess)
1557 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001558 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001559
reed1f836ee2014-07-07 07:49:34 -07001560 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001561}
1562
reed@google.com819c9212011-02-23 18:56:55 +00001563#ifdef SK_DEBUG
1564void SkCanvas::validateClip() const {
1565 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001566 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001567 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001568 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001569 return;
1570 }
1571
reed@google.com819c9212011-02-23 18:56:55 +00001572 SkIRect ir;
1573 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001574 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001575
reed687fa1c2015-04-07 08:00:56 -07001576 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001577 const SkClipStack::Element* element;
1578 while ((element = iter.next()) != NULL) {
1579 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001580 case SkClipStack::Element::kRect_Type:
1581 element->getRect().round(&ir);
1582 tmpClip.op(ir, element->getOp());
1583 break;
1584 case SkClipStack::Element::kEmpty_Type:
1585 tmpClip.setEmpty();
1586 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001587 default: {
1588 SkPath path;
1589 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001590 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001591 break;
1592 }
reed@google.com819c9212011-02-23 18:56:55 +00001593 }
1594 }
reed@google.com819c9212011-02-23 18:56:55 +00001595}
1596#endif
1597
reed@google.com90c07ea2012-04-13 13:50:27 +00001598void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001599 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001600 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001601
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001602 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001603 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001604 }
1605}
1606
reed@google.com5c3d1472011-02-22 19:12:23 +00001607///////////////////////////////////////////////////////////////////////////////
1608
reed@google.com754de5f2014-02-24 19:38:20 +00001609bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001610 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001611}
1612
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001613bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001614 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001615}
1616
reed@google.com3b3e8952012-08-16 20:53:31 +00001617bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001618 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001619 return true;
1620
reed1f836ee2014-07-07 07:49:34 -07001621 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001622 return true;
1623 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001624
reed1f836ee2014-07-07 07:49:34 -07001625 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001626 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001627 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001628 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001629 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001630 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001631
reed@android.coma380ae42009-07-21 01:17:02 +00001632 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001633 // TODO: should we use | instead, or compare all 4 at once?
1634 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001635 return true;
1636 }
reed@google.comc0784db2013-12-13 21:16:12 +00001637 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001638 return true;
1639 }
1640 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001641 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001642}
1643
reed@google.com3b3e8952012-08-16 20:53:31 +00001644bool SkCanvas::quickReject(const SkPath& path) const {
1645 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001646}
1647
reed@google.com3b3e8952012-08-16 20:53:31 +00001648bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001649 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001650 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001651 return false;
1652 }
1653
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001654 SkMatrix inverse;
1655 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001656 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001657 if (bounds) {
1658 bounds->setEmpty();
1659 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001660 return false;
1661 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001662
bsalomon49f085d2014-09-05 13:34:00 -07001663 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001664 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001665 // adjust it outwards in case we are antialiasing
1666 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001667
reed@google.com8f4d2302013-12-17 16:44:46 +00001668 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1669 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001670 inverse.mapRect(bounds, r);
1671 }
1672 return true;
1673}
1674
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001675bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001676 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001677 if (clip.isEmpty()) {
1678 if (bounds) {
1679 bounds->setEmpty();
1680 }
1681 return false;
1682 }
1683
bsalomon49f085d2014-09-05 13:34:00 -07001684 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001685 *bounds = clip.getBounds();
1686 }
1687 return true;
1688}
1689
reed@android.com8a1c16f2008-12-17 15:59:43 +00001690const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001691 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001692}
1693
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001694const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001695 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001696}
1697
reed@google.com9c135db2014-03-12 18:28:35 +00001698GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1699 SkBaseDevice* dev = this->getTopDevice();
1700 return dev ? dev->accessRenderTarget() : NULL;
1701}
1702
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001703GrContext* SkCanvas::getGrContext() {
1704#if SK_SUPPORT_GPU
1705 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001706 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001707 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001708 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001709 return renderTarget->getContext();
1710 }
1711 }
1712#endif
1713
1714 return NULL;
1715
1716}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001717
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001718void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1719 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001720 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001721 if (outer.isEmpty()) {
1722 return;
1723 }
1724 if (inner.isEmpty()) {
1725 this->drawRRect(outer, paint);
1726 return;
1727 }
1728
1729 // We don't have this method (yet), but technically this is what we should
1730 // be able to assert...
1731 // SkASSERT(outer.contains(inner));
1732 //
1733 // For now at least check for containment of bounds
1734 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1735
1736 this->onDrawDRRect(outer, inner, paint);
1737}
1738
reed41af9662015-01-05 07:49:08 -08001739// These need to stop being virtual -- clients need to override the onDraw... versions
1740
1741void SkCanvas::drawPaint(const SkPaint& paint) {
1742 this->onDrawPaint(paint);
1743}
1744
1745void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1746 this->onDrawRect(r, paint);
1747}
1748
1749void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1750 this->onDrawOval(r, paint);
1751}
1752
1753void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1754 this->onDrawRRect(rrect, paint);
1755}
1756
1757void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1758 this->onDrawPoints(mode, count, pts, paint);
1759}
1760
1761void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1762 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1763 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1764 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1765 indices, indexCount, paint);
1766}
1767
1768void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1769 this->onDrawPath(path, paint);
1770}
1771
reeda85d4d02015-05-06 12:56:48 -07001772void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1773 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001774}
1775
1776void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1777 const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07001778 if (dst.isEmpty()) {
1779 return;
1780 }
reed41af9662015-01-05 07:49:08 -08001781 this->onDrawImageRect(image, src, dst, paint);
1782}
1783
1784void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001785 if (bitmap.empty()) {
1786 return;
1787 }
reed41af9662015-01-05 07:49:08 -08001788 this->onDrawBitmap(bitmap, dx, dy, paint);
1789}
1790
1791void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1792 const SkPaint* paint, DrawBitmapRectFlags flags) {
tomhudson2df6fd62015-04-09 09:20:19 -07001793 if (bitmap.empty()) {
1794 return;
1795 }
reed41af9662015-01-05 07:49:08 -08001796 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1797}
1798
1799void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1800 const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001801 if (bitmap.empty()) {
1802 return;
1803 }
reed41af9662015-01-05 07:49:08 -08001804 this->onDrawBitmapNine(bitmap, center, dst, paint);
1805}
1806
1807void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001808 if (bitmap.empty()) {
1809 return;
1810 }
reed41af9662015-01-05 07:49:08 -08001811 this->onDrawSprite(bitmap, left, top, paint);
1812}
1813
reed@android.com8a1c16f2008-12-17 15:59:43 +00001814//////////////////////////////////////////////////////////////////////////////
1815// These are the virtual drawing methods
1816//////////////////////////////////////////////////////////////////////////////
1817
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001818void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001819 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001820 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1821 }
1822}
1823
reed41af9662015-01-05 07:49:08 -08001824void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001825 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001826 this->internalDrawPaint(paint);
1827}
1828
1829void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001830 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001831
1832 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001833 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001834 }
1835
reed@google.com4e2b3d32011-04-07 14:18:59 +00001836 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001837}
1838
reed41af9662015-01-05 07:49:08 -08001839void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1840 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001841 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001842 if ((long)count <= 0) {
1843 return;
1844 }
1845
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001846 SkRect r, storage;
1847 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001848 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001849 // special-case 2 points (common for drawing a single line)
1850 if (2 == count) {
1851 r.set(pts[0], pts[1]);
1852 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001853 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001854 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001855 bounds = &paint.computeFastStrokeBounds(r, &storage);
1856 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001857 return;
1858 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001859 }
reed@google.coma584aed2012-05-16 14:06:02 +00001860
reed@android.com8a1c16f2008-12-17 15:59:43 +00001861 SkASSERT(pts != NULL);
1862
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001863 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001864
reed@android.com8a1c16f2008-12-17 15:59:43 +00001865 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001866 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001867 }
reed@google.com4b226022011-01-11 18:32:13 +00001868
reed@google.com4e2b3d32011-04-07 14:18:59 +00001869 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001870}
1871
reed41af9662015-01-05 07:49:08 -08001872void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001873 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001874 SkRect storage;
1875 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001876 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001877 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1878 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1879 SkRect tmp(r);
1880 tmp.sort();
1881
1882 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001883 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001884 return;
1885 }
1886 }
reed@google.com4b226022011-01-11 18:32:13 +00001887
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001888 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001889
1890 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001891 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001892 }
1893
reed@google.com4e2b3d32011-04-07 14:18:59 +00001894 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001895}
1896
reed41af9662015-01-05 07:49:08 -08001897void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001898 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001899 SkRect storage;
1900 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001901 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001902 bounds = &paint.computeFastBounds(oval, &storage);
1903 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001904 return;
1905 }
1906 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001907
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001908 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001909
1910 while (iter.next()) {
1911 iter.fDevice->drawOval(iter, oval, looper.paint());
1912 }
1913
1914 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001915}
1916
reed41af9662015-01-05 07:49:08 -08001917void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001918 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001919 SkRect storage;
1920 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001921 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001922 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1923 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001924 return;
1925 }
1926 }
1927
1928 if (rrect.isRect()) {
1929 // call the non-virtual version
1930 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001931 return;
1932 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001933 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001934 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1935 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001936 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001937
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001938 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001939
1940 while (iter.next()) {
1941 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1942 }
1943
1944 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001945}
1946
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001947void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1948 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001949 SkRect storage;
1950 const SkRect* bounds = NULL;
1951 if (paint.canComputeFastBounds()) {
1952 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1953 if (this->quickReject(*bounds)) {
1954 return;
1955 }
1956 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001957
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001958 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001959
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001960 while (iter.next()) {
1961 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1962 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001963
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001964 LOOPER_END
1965}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001966
reed41af9662015-01-05 07:49:08 -08001967void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001968 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001969 if (!path.isFinite()) {
1970 return;
1971 }
1972
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001973 SkRect storage;
1974 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001975 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001976 const SkRect& pathBounds = path.getBounds();
1977 bounds = &paint.computeFastBounds(pathBounds, &storage);
1978 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001979 return;
1980 }
1981 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001982
1983 const SkRect& r = path.getBounds();
1984 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001985 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001986 this->internalDrawPaint(paint);
1987 }
1988 return;
1989 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001990
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001991 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001992
1993 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001994 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001995 }
1996
reed@google.com4e2b3d32011-04-07 14:18:59 +00001997 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001998}
1999
reeda85d4d02015-05-06 12:56:48 -07002000void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002001 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002002 SkRect bounds = SkRect::MakeXYWH(x, y,
2003 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
2004 if (NULL == paint || paint->canComputeFastBounds()) {
2005 if (paint) {
2006 paint->computeFastBounds(bounds, &bounds);
2007 }
2008 if (this->quickReject(bounds)) {
2009 return;
2010 }
2011 }
2012
2013 SkLazyPaint lazy;
2014 if (NULL == paint) {
2015 paint = lazy.init();
2016 }
2017
2018 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds)
2019
2020 while (iter.next()) {
2021 iter.fDevice->drawImage(iter, image, x, y, looper.paint());
2022 }
2023
2024 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002025}
2026
reed41af9662015-01-05 07:49:08 -08002027void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2028 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002029 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
reeda85d4d02015-05-06 12:56:48 -07002030 SkRect storage;
2031 const SkRect* bounds = &dst;
2032 if (NULL == paint || paint->canComputeFastBounds()) {
2033 if (paint) {
2034 bounds = &paint->computeFastBounds(dst, &storage);
2035 }
2036 if (this->quickReject(*bounds)) {
2037 return;
2038 }
2039 }
2040 SkLazyPaint lazy;
2041 if (NULL == paint) {
2042 paint = lazy.init();
2043 }
2044
2045 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2046
2047 while (iter.next()) {
2048 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint());
2049 }
2050
2051 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002052}
2053
reed41af9662015-01-05 07:49:08 -08002054void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002055 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002056 SkDEBUGCODE(bitmap.validate();)
2057
reed@google.com3d608122011-11-21 15:16:16 +00002058 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002059 SkRect bounds = {
2060 x, y,
2061 x + SkIntToScalar(bitmap.width()),
2062 y + SkIntToScalar(bitmap.height())
2063 };
2064 if (paint) {
2065 (void)paint->computeFastBounds(bounds, &bounds);
2066 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002067 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002068 return;
2069 }
2070 }
reed@google.com4b226022011-01-11 18:32:13 +00002071
reed@android.com8a1c16f2008-12-17 15:59:43 +00002072 SkMatrix matrix;
2073 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00002074 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002075}
2076
reed@google.com9987ec32011-09-07 11:57:52 +00002077// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002078void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002079 const SkRect& dst, const SkPaint* paint,
2080 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002081 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002082 return;
2083 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002084
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002085 SkRect storage;
2086 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00002087 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002088 if (paint) {
2089 bounds = &paint->computeFastBounds(dst, &storage);
2090 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002091 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002092 return;
2093 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002094 }
reed@google.com3d608122011-11-21 15:16:16 +00002095
reed@google.com33535f32012-09-25 15:37:50 +00002096 SkLazyPaint lazy;
2097 if (NULL == paint) {
2098 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002099 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002100
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002101 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002102
reed@google.com33535f32012-09-25 15:37:50 +00002103 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002104 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00002105 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002106
reed@google.com33535f32012-09-25 15:37:50 +00002107 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002108}
2109
reed41af9662015-01-05 07:49:08 -08002110void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2111 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08002112 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002113 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002114 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00002115}
2116
reed@google.com9987ec32011-09-07 11:57:52 +00002117void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
2118 const SkIRect& center, const SkRect& dst,
2119 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002120 if (bitmap.drawsNothing()) {
2121 return;
2122 }
reed@google.com3d608122011-11-21 15:16:16 +00002123 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00002124 SkRect storage;
2125 const SkRect* bounds = &dst;
2126 if (paint) {
2127 bounds = &paint->computeFastBounds(dst, &storage);
2128 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002129 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002130 return;
2131 }
2132 }
2133
reed@google.com9987ec32011-09-07 11:57:52 +00002134 const int32_t w = bitmap.width();
2135 const int32_t h = bitmap.height();
2136
2137 SkIRect c = center;
2138 // pin center to the bounds of the bitmap
2139 c.fLeft = SkMax32(0, center.fLeft);
2140 c.fTop = SkMax32(0, center.fTop);
2141 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2142 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2143
reed@google.com71121732012-09-18 15:14:33 +00002144 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002145 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00002146 };
2147 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002148 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00002149 };
reed@google.com9987ec32011-09-07 11:57:52 +00002150 SkScalar dstX[4] = {
2151 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2152 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2153 };
2154 SkScalar dstY[4] = {
2155 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2156 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2157 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002158
reed@google.com9987ec32011-09-07 11:57:52 +00002159 if (dstX[1] > dstX[2]) {
2160 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2161 dstX[2] = dstX[1];
2162 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002163
reed@google.com9987ec32011-09-07 11:57:52 +00002164 if (dstY[1] > dstY[2]) {
2165 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2166 dstY[2] = dstY[1];
2167 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002168
reed@google.com9987ec32011-09-07 11:57:52 +00002169 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00002170 SkRect s, d;
2171
reed@google.com9987ec32011-09-07 11:57:52 +00002172 s.fTop = srcY[y];
2173 s.fBottom = srcY[y+1];
2174 d.fTop = dstY[y];
2175 d.fBottom = dstY[y+1];
2176 for (int x = 0; x < 3; x++) {
2177 s.fLeft = srcX[x];
2178 s.fRight = srcX[x+1];
2179 d.fLeft = dstX[x];
2180 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002181 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00002182 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00002183 }
2184 }
2185}
2186
reed41af9662015-01-05 07:49:08 -08002187void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2188 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002189 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002190 SkDEBUGCODE(bitmap.validate();)
2191
2192 // Need a device entry-point, so gpu can use a mesh
2193 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2194}
2195
reed@google.comf67e4cf2011-03-15 20:56:58 +00002196class SkDeviceFilteredPaint {
2197public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002198 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002199 uint32_t filteredFlags = device->filterTextFlags(paint);
2200 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002201 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002202 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002203 fPaint = newPaint;
2204 } else {
2205 fPaint = &paint;
2206 }
2207 }
2208
reed@google.comf67e4cf2011-03-15 20:56:58 +00002209 const SkPaint& paint() const { return *fPaint; }
2210
2211private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002212 const SkPaint* fPaint;
2213 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002214};
2215
bungeman@google.com52c748b2011-08-22 21:30:43 +00002216void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2217 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002218 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002219 draw.fDevice->drawRect(draw, r, paint);
2220 } else {
2221 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002222 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002223 draw.fDevice->drawRect(draw, r, p);
2224 }
2225}
2226
2227void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2228 const char text[], size_t byteLength,
2229 SkScalar x, SkScalar y) {
2230 SkASSERT(byteLength == 0 || text != NULL);
2231
2232 // nothing to draw
2233 if (text == NULL || byteLength == 0 ||
2234 draw.fClip->isEmpty() ||
2235 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2236 return;
2237 }
2238
2239 SkScalar width = 0;
2240 SkPoint start;
2241
2242 start.set(0, 0); // to avoid warning
2243 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2244 SkPaint::kStrikeThruText_Flag)) {
2245 width = paint.measureText(text, byteLength);
2246
2247 SkScalar offsetX = 0;
2248 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2249 offsetX = SkScalarHalf(width);
2250 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2251 offsetX = width;
2252 }
2253 start.set(x - offsetX, y);
2254 }
2255
2256 if (0 == width) {
2257 return;
2258 }
2259
2260 uint32_t flags = paint.getFlags();
2261
2262 if (flags & (SkPaint::kUnderlineText_Flag |
2263 SkPaint::kStrikeThruText_Flag)) {
2264 SkScalar textSize = paint.getTextSize();
2265 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2266 SkRect r;
2267
2268 r.fLeft = start.fX;
2269 r.fRight = start.fX + width;
2270
2271 if (flags & SkPaint::kUnderlineText_Flag) {
2272 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2273 start.fY);
2274 r.fTop = offset;
2275 r.fBottom = offset + height;
2276 DrawRect(draw, paint, r, textSize);
2277 }
2278 if (flags & SkPaint::kStrikeThruText_Flag) {
2279 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2280 start.fY);
2281 r.fTop = offset;
2282 r.fBottom = offset + height;
2283 DrawRect(draw, paint, r, textSize);
2284 }
2285 }
2286}
2287
reed@google.come0d9ce82014-04-23 04:00:17 +00002288void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2289 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002290 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002291
2292 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002293 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002294 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002295 DrawTextDecorations(iter, dfp.paint(),
2296 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002297 }
2298
reed@google.com4e2b3d32011-04-07 14:18:59 +00002299 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002300}
2301
reed@google.come0d9ce82014-04-23 04:00:17 +00002302void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2303 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002304 SkPoint textOffset = SkPoint::Make(0, 0);
2305
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002306 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002307
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002309 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002310 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002311 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002312 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002313
reed@google.com4e2b3d32011-04-07 14:18:59 +00002314 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002315}
2316
reed@google.come0d9ce82014-04-23 04:00:17 +00002317void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2318 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002319
2320 SkPoint textOffset = SkPoint::Make(0, constY);
2321
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002322 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002323
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002325 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002326 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002327 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002328 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002329
reed@google.com4e2b3d32011-04-07 14:18:59 +00002330 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002331}
2332
reed@google.come0d9ce82014-04-23 04:00:17 +00002333void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2334 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002335 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002336
reed@android.com8a1c16f2008-12-17 15:59:43 +00002337 while (iter.next()) {
2338 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002339 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002340 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002341
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002342 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002343}
2344
fmalita00d5c2c2014-08-21 08:53:26 -07002345void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2346 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002347
fmalita85d5eb92015-03-04 11:20:12 -08002348 SkRect storage;
2349 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002350 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002351 storage = blob->bounds().makeOffset(x, y);
2352 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002353
fmalita85d5eb92015-03-04 11:20:12 -08002354 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002355 return;
2356 }
2357 }
2358
fmalita024f9962015-03-03 19:08:17 -08002359 // We cannot filter in the looper as we normally do, because the paint is
2360 // incomplete at this point (text-related attributes are embedded within blob run paints).
2361 SkDrawFilter* drawFilter = fMCRec->fFilter;
2362 fMCRec->fFilter = NULL;
2363
fmalita85d5eb92015-03-04 11:20:12 -08002364 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002365
fmalitaaa1b9122014-08-28 14:32:24 -07002366 while (iter.next()) {
2367 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002368 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002369 }
2370
fmalitaaa1b9122014-08-28 14:32:24 -07002371 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002372
2373 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002374}
2375
reed@google.come0d9ce82014-04-23 04:00:17 +00002376// These will become non-virtual, so they always call the (virtual) onDraw... method
2377void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2378 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002379 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002380 this->onDrawText(text, byteLength, x, y, paint);
2381}
2382void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2383 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002384 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002385 this->onDrawPosText(text, byteLength, pos, paint);
2386}
2387void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2388 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002389 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002390 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2391}
2392void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2393 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002394 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002395 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2396}
fmalita00d5c2c2014-08-21 08:53:26 -07002397void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2398 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002399 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002400 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002401 this->onDrawTextBlob(blob, x, y, paint);
2402 }
2403}
reed@google.come0d9ce82014-04-23 04:00:17 +00002404
reed41af9662015-01-05 07:49:08 -08002405void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2406 const SkPoint verts[], const SkPoint texs[],
2407 const SkColor colors[], SkXfermode* xmode,
2408 const uint16_t indices[], int indexCount,
2409 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002410 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002411 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002412
reed@android.com8a1c16f2008-12-17 15:59:43 +00002413 while (iter.next()) {
2414 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002415 colors, xmode, indices, indexCount,
2416 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002417 }
reed@google.com4b226022011-01-11 18:32:13 +00002418
reed@google.com4e2b3d32011-04-07 14:18:59 +00002419 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002420}
2421
dandovb3c9d1c2014-08-12 08:34:29 -07002422void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2423 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002424 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002425 if (NULL == cubics) {
2426 return;
2427 }
mtklein6cfa73a2014-08-13 13:33:49 -07002428
dandovecfff212014-08-04 10:02:00 -07002429 // Since a patch is always within the convex hull of the control points, we discard it when its
2430 // bounding rectangle is completely outside the current clip.
2431 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002432 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002433 if (this->quickReject(bounds)) {
2434 return;
2435 }
mtklein6cfa73a2014-08-13 13:33:49 -07002436
dandovb3c9d1c2014-08-12 08:34:29 -07002437 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2438}
2439
2440void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2441 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2442
dandovecfff212014-08-04 10:02:00 -07002443 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002444
dandovecfff212014-08-04 10:02:00 -07002445 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002446 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002447 }
mtklein6cfa73a2014-08-13 13:33:49 -07002448
dandovecfff212014-08-04 10:02:00 -07002449 LOOPER_END
2450}
2451
reed3cb38402015-02-06 08:36:15 -08002452void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002453 if (dr && !this->quickReject(dr->getBounds())) {
2454 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002455 }
2456}
2457
reed3cb38402015-02-06 08:36:15 -08002458void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002459 dr->draw(this);
2460}
2461
reed@android.com8a1c16f2008-12-17 15:59:43 +00002462//////////////////////////////////////////////////////////////////////////////
2463// These methods are NOT virtual, and therefore must call back into virtual
2464// methods, rather than actually drawing themselves.
2465//////////////////////////////////////////////////////////////////////////////
2466
2467void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002468 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002469 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002470 SkPaint paint;
2471
2472 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002473 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002474 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002475 }
2476 this->drawPaint(paint);
2477}
2478
reed@android.com845fdac2009-06-23 03:01:32 +00002479void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002480 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002481 SkPaint paint;
2482
2483 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002484 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002485 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002486 }
2487 this->drawPaint(paint);
2488}
2489
2490void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002491 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002492 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002493
reed@android.com8a1c16f2008-12-17 15:59:43 +00002494 pt.set(x, y);
2495 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2496}
2497
2498void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002499 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002500 SkPoint pt;
2501 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002502
reed@android.com8a1c16f2008-12-17 15:59:43 +00002503 pt.set(x, y);
2504 paint.setColor(color);
2505 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2506}
2507
2508void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2509 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002510 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002511 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002512
reed@android.com8a1c16f2008-12-17 15:59:43 +00002513 pts[0].set(x0, y0);
2514 pts[1].set(x1, y1);
2515 this->drawPoints(kLines_PointMode, 2, pts, paint);
2516}
2517
2518void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2519 SkScalar right, SkScalar bottom,
2520 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002521 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002522 SkRect r;
2523
2524 r.set(left, top, right, bottom);
2525 this->drawRect(r, paint);
2526}
2527
2528void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2529 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002530 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002531 if (radius < 0) {
2532 radius = 0;
2533 }
2534
2535 SkRect r;
2536 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002537 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002538}
2539
2540void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2541 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002542 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002543 if (rx > 0 && ry > 0) {
2544 if (paint.canComputeFastBounds()) {
2545 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002546 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002547 return;
2548 }
2549 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002550 SkRRect rrect;
2551 rrect.setRectXY(r, rx, ry);
2552 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002553 } else {
2554 this->drawRect(r, paint);
2555 }
2556}
2557
reed@android.com8a1c16f2008-12-17 15:59:43 +00002558void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2559 SkScalar sweepAngle, bool useCenter,
2560 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002561 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002562 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2563 this->drawOval(oval, paint);
2564 } else {
2565 SkPath path;
2566 if (useCenter) {
2567 path.moveTo(oval.centerX(), oval.centerY());
2568 }
2569 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2570 if (useCenter) {
2571 path.close();
2572 }
2573 this->drawPath(path, paint);
2574 }
2575}
2576
2577void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2578 const SkPath& path, SkScalar hOffset,
2579 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002580 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002581 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002582
reed@android.com8a1c16f2008-12-17 15:59:43 +00002583 matrix.setTranslate(hOffset, vOffset);
2584 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2585}
2586
reed@android.comf76bacf2009-05-13 14:00:33 +00002587///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002588
2589/**
2590 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2591 * against the playback cost of recursing into the subpicture to get at its actual ops.
2592 *
2593 * For now we pick a conservatively small value, though measurement (and other heuristics like
2594 * the type of ops contained) may justify changing this value.
2595 */
2596#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002597
reedd5fa1a42014-08-09 11:08:05 -07002598void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002599 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002600 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002601 if (matrix && matrix->isIdentity()) {
2602 matrix = NULL;
2603 }
reed1c2c4412015-04-30 13:09:24 -07002604 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2605 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2606 picture->playback(this);
2607 } else {
2608 this->onDrawPicture(picture, matrix, paint);
2609 }
reedd5fa1a42014-08-09 11:08:05 -07002610 }
2611}
robertphillips9b14f262014-06-04 05:40:44 -07002612
reedd5fa1a42014-08-09 11:08:05 -07002613void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2614 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002615 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002616 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002617 // Canvas has to first give the device the opportunity to render
2618 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002619 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002620 return; // the device has rendered the entire picture
2621 }
2622 }
2623
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002624 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002625 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002626}
2627
reed@android.com8a1c16f2008-12-17 15:59:43 +00002628///////////////////////////////////////////////////////////////////////////////
2629///////////////////////////////////////////////////////////////////////////////
2630
2631SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002632 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002633
2634 SkASSERT(canvas);
2635
2636 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2637 fDone = !fImpl->next();
2638}
2639
2640SkCanvas::LayerIter::~LayerIter() {
2641 fImpl->~SkDrawIter();
2642}
2643
2644void SkCanvas::LayerIter::next() {
2645 fDone = !fImpl->next();
2646}
2647
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002648SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002649 return fImpl->getDevice();
2650}
2651
2652const SkMatrix& SkCanvas::LayerIter::matrix() const {
2653 return fImpl->getMatrix();
2654}
2655
2656const SkPaint& SkCanvas::LayerIter::paint() const {
2657 const SkPaint* paint = fImpl->getPaint();
2658 if (NULL == paint) {
2659 paint = &fDefaultPaint;
2660 }
2661 return *paint;
2662}
2663
2664const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2665int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2666int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002667
2668///////////////////////////////////////////////////////////////////////////////
2669
fmalitac3b589a2014-06-05 12:40:07 -07002670SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002671
2672///////////////////////////////////////////////////////////////////////////////
2673
2674static bool supported_for_raster_canvas(const SkImageInfo& info) {
2675 switch (info.alphaType()) {
2676 case kPremul_SkAlphaType:
2677 case kOpaque_SkAlphaType:
2678 break;
2679 default:
2680 return false;
2681 }
2682
2683 switch (info.colorType()) {
2684 case kAlpha_8_SkColorType:
2685 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002686 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002687 break;
2688 default:
2689 return false;
2690 }
2691
2692 return true;
2693}
2694
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002695SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2696 if (!supported_for_raster_canvas(info)) {
2697 return NULL;
2698 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002699
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002700 SkBitmap bitmap;
2701 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2702 return NULL;
2703 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002704 return SkNEW_ARGS(SkCanvas, (bitmap));
2705}
reedd5fa1a42014-08-09 11:08:05 -07002706
2707///////////////////////////////////////////////////////////////////////////////
2708
2709SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002710 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002711 : fCanvas(canvas)
2712 , fSaveCount(canvas->getSaveCount())
2713{
bsalomon49f085d2014-09-05 13:34:00 -07002714 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002715 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002716 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002717 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002718 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002719 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002720 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002721 canvas->save();
2722 }
mtklein6cfa73a2014-08-13 13:33:49 -07002723
bsalomon49f085d2014-09-05 13:34:00 -07002724 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002725 canvas->concat(*matrix);
2726 }
2727}
2728
2729SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2730 fCanvas->restoreToCount(fSaveCount);
2731}