blob: fcfb6414075da44c6e5f148d5987b3deaa936241 [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) {
robertphillipsefbffed2015-06-22 12:06:08 -0700539 // The root device and the canvas should always have the same pixel geometry
540 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().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
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000598SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000599 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700600 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000601{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000602 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700603
reedd9544982014-09-09 18:46:22 -0700604 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000605}
606
robertphillipsfcf78292015-06-19 11:49:52 -0700607SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
608 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700609 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700610{
611 inc_canvas();
612
613 this->init(device, flags);
614}
615
reed4a8126e2014-09-22 07:29:03 -0700616SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700617 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700618 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700619{
620 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700621
robertphillipsfcf78292015-06-19 11:49:52 -0700622 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap, fProps)));
reed4a8126e2014-09-22 07:29:03 -0700623 this->init(device, kDefault_InitFlags);
624}
reed29c857d2014-09-21 10:25:07 -0700625
reed4a8126e2014-09-22 07:29:03 -0700626SkCanvas::SkCanvas(const SkBitmap& bitmap)
627 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
628 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
629{
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);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000634}
635
636SkCanvas::~SkCanvas() {
637 // free up the contents of our deque
638 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000639
reed@android.com8a1c16f2008-12-17 15:59:43 +0000640 this->internalRestore(); // restore the last, since we're going away
641
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000642 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000643
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644 dec_canvas();
645}
646
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647SkDrawFilter* SkCanvas::getDrawFilter() const {
648 return fMCRec->fFilter;
649}
650
651SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700652 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
654 return filter;
655}
656
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000657SkMetaData& SkCanvas::getMetaData() {
658 // metadata users are rare, so we lazily allocate it. If that changes we
659 // can decide to just make it a field in the device (rather than a ptr)
660 if (NULL == fMetaData) {
661 fMetaData = new SkMetaData;
662 }
663 return *fMetaData;
664}
665
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666///////////////////////////////////////////////////////////////////////////////
667
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000668void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000669 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000670 if (device) {
671 device->flush();
672 }
673}
674
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000675SkISize SkCanvas::getTopLayerSize() const {
676 SkBaseDevice* d = this->getTopDevice();
677 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
678}
679
680SkIPoint SkCanvas::getTopLayerOrigin() const {
681 SkBaseDevice* d = this->getTopDevice();
682 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
683}
684
685SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000686 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000687 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
688}
689
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000690SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000692 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693 SkASSERT(rec && rec->fLayer);
694 return rec->fLayer->fDevice;
695}
696
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000697SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000698 if (updateMatrixClip) {
699 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
700 }
reed@google.com9266fed2011-03-30 00:18:03 +0000701 return fMCRec->fTopLayer->fDevice;
702}
703
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000704bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
705 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
706 return false;
707 }
708
709 bool weAllocated = false;
710 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700711 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000712 return false;
713 }
714 weAllocated = true;
715 }
716
reedcf01e312015-05-23 19:14:51 -0700717 SkAutoPixmapUnlock unlocker;
718 if (bitmap->requestLock(&unlocker)) {
719 const SkPixmap& pm = unlocker.pixmap();
720 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
721 return true;
722 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000723 }
724
725 if (weAllocated) {
726 bitmap->setPixelRef(NULL);
727 }
728 return false;
729}
reed@google.com51df9e32010-12-23 19:29:18 +0000730
bsalomon@google.comc6980972011-11-02 19:57:21 +0000731bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000732 SkIRect r = srcRect;
733 const SkISize size = this->getBaseLayerSize();
734 if (!r.intersect(0, 0, size.width(), size.height())) {
735 bitmap->reset();
736 return false;
737 }
738
reed84825042014-09-02 12:50:45 -0700739 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000740 // bitmap will already be reset.
741 return false;
742 }
743 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
744 bitmap->reset();
745 return false;
746 }
747 return true;
748}
749
reed96472de2014-12-10 09:53:42 -0800750bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000751 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000752 if (!device) {
753 return false;
754 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000755 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800756
reed96472de2014-12-10 09:53:42 -0800757 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
758 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000759 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000760 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000761
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000762 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800763 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000764}
765
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000766bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
767 if (bitmap.getTexture()) {
768 return false;
769 }
reedcf01e312015-05-23 19:14:51 -0700770
771 SkAutoPixmapUnlock unlocker;
772 if (bitmap.requestLock(&unlocker)) {
773 const SkPixmap& pm = unlocker.pixmap();
774 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000775 }
776 return false;
777}
778
779bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
780 int x, int y) {
781 switch (origInfo.colorType()) {
782 case kUnknown_SkColorType:
783 case kIndex_8_SkColorType:
784 return false;
785 default:
786 break;
787 }
788 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
789 return false;
790 }
791
792 const SkISize size = this->getBaseLayerSize();
793 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
794 if (!target.intersect(0, 0, size.width(), size.height())) {
795 return false;
796 }
797
798 SkBaseDevice* device = this->getDevice();
799 if (!device) {
800 return false;
801 }
802
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000803 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700804 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000805
806 // if x or y are negative, then we have to adjust pixels
807 if (x > 0) {
808 x = 0;
809 }
810 if (y > 0) {
811 y = 0;
812 }
813 // here x,y are either 0 or negative
814 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
815
reed4af35f32014-06-27 17:47:49 -0700816 // Tell our owning surface to bump its generation ID
817 this->predrawNotify();
818
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000819 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000820 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000821}
reed@google.com51df9e32010-12-23 19:29:18 +0000822
junov@google.com4370aed2012-01-18 16:21:08 +0000823SkCanvas* SkCanvas::canvasForDrawIter() {
824 return this;
825}
826
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827//////////////////////////////////////////////////////////////////////////////
828
reed@android.com8a1c16f2008-12-17 15:59:43 +0000829void SkCanvas::updateDeviceCMCache() {
830 if (fDeviceCMDirty) {
831 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700832 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000833 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000834
reed@android.com8a1c16f2008-12-17 15:59:43 +0000835 if (NULL == layer->fNext) { // only one layer
reed687fa1c2015-04-07 08:00:56 -0700836 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000837 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000838 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000839 do {
reed687fa1c2015-04-07 08:00:56 -0700840 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000841 } while ((layer = layer->fNext) != NULL);
842 }
843 fDeviceCMDirty = false;
844 }
845}
846
reed@android.com8a1c16f2008-12-17 15:59:43 +0000847///////////////////////////////////////////////////////////////////////////////
848
reed2ff1fce2014-12-11 07:07:37 -0800849void SkCanvas::checkForDeferredSave() {
850 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800851 this->doSave();
852 }
853}
854
reedf0090cb2014-11-26 08:55:51 -0800855int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800856#ifdef SK_DEBUG
857 int count = 0;
858 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
859 for (;;) {
860 const MCRec* rec = (const MCRec*)iter.next();
861 if (!rec) {
862 break;
863 }
864 count += 1 + rec->fDeferredSaveCount;
865 }
866 SkASSERT(count == fSaveCount);
867#endif
868 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800869}
870
871int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800872 fSaveCount += 1;
873 fMCRec->fDeferredSaveCount += 1;
874 return this->getSaveCount() - 1; // return our prev value
875}
876
877void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800878 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700879
880 SkASSERT(fMCRec->fDeferredSaveCount > 0);
881 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800882 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800883}
884
885void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800886 if (fMCRec->fDeferredSaveCount > 0) {
887 SkASSERT(fSaveCount > 1);
888 fSaveCount -= 1;
889 fMCRec->fDeferredSaveCount -= 1;
890 } else {
891 // check for underflow
892 if (fMCStack.count() > 1) {
893 this->willRestore();
894 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700895 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800896 this->internalRestore();
897 this->didRestore();
898 }
reedf0090cb2014-11-26 08:55:51 -0800899 }
900}
901
902void SkCanvas::restoreToCount(int count) {
903 // sanity check
904 if (count < 1) {
905 count = 1;
906 }
mtkleinf0f14112014-12-12 08:46:25 -0800907
reedf0090cb2014-11-26 08:55:51 -0800908 int n = this->getSaveCount() - count;
909 for (int i = 0; i < n; ++i) {
910 this->restore();
911 }
912}
913
reed2ff1fce2014-12-11 07:07:37 -0800914void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000915 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700916 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000917 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000918
reed687fa1c2015-04-07 08:00:56 -0700919 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000920}
921
reed@android.com8a1c16f2008-12-17 15:59:43 +0000922static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000923#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000924 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000925#else
926 return true;
927#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000928}
929
junov@chromium.orga907ac32012-02-24 21:54:07 +0000930bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700931 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000932 SkIRect clipBounds;
933 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000934 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000935 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000936
reed96e657d2015-03-10 17:30:07 -0700937 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
938
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000939 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700940 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000941 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000942 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700943 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000944 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000945
reed96e657d2015-03-10 17:30:07 -0700946 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000947 r.roundOut(&ir);
948 // early exit if the layer's bounds are clipped out
949 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000950 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700951 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700952 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000953 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000954 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955 }
956 } else { // no user bounds, so just use the clip
957 ir = clipBounds;
958 }
reed180aec42015-03-11 10:39:04 -0700959 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000960
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000961 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -0700962 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -0700963 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -0700964 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -0700965 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000966 }
967
968 if (intersection) {
969 *intersection = ir;
970 }
971 return true;
972}
973
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000974int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800975 if (gIgnoreSaveLayerBounds) {
976 bounds = NULL;
977 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000978 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -0700979 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700980 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800981 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000982}
983
reed2ff1fce2014-12-11 07:07:37 -0800984int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800985 if (gIgnoreSaveLayerBounds) {
986 bounds = NULL;
987 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000988 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -0700989 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700990 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800991 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000992}
993
reed2ff1fce2014-12-11 07:07:37 -0800994void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -0700995 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000996#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000997 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000998#endif
999
junov@chromium.orga907ac32012-02-24 21:54:07 +00001000 // do this before we create the layer. We don't call the public save() since
1001 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001002 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001003
1004 fDeviceCMDirty = true;
1005
1006 SkIRect ir;
reeddaa57bf2015-05-15 10:39:17 -07001007 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -08001008 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001009 }
1010
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001011 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1012 // the clipRectBounds() call above?
1013 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001014 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001015 }
1016
reed76033be2015-03-14 10:54:31 -07001017 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001018 SkPixelGeometry geo = fProps.pixelGeometry();
1019 if (paint) {
reed76033be2015-03-14 10:54:31 -07001020 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001021 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001022 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001023 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001024 }
1025 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001026 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1027 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001028
reedb2db8982014-11-13 12:41:02 -08001029 SkBaseDevice* device = this->getTopDevice();
1030 if (NULL == device) {
1031 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001032 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001033 }
reedb2db8982014-11-13 12:41:02 -08001034
reed61f501f2015-04-29 08:34:00 -07001035 bool forceSpriteOnRestore = false;
1036 {
reeddaa57bf2015-05-15 10:39:17 -07001037 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed61f501f2015-04-29 08:34:00 -07001038 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo);
1039 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
1040 if (NULL == newDev) {
1041 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001042 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1043 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
reed61f501f2015-04-29 08:34:00 -07001044 if (NULL == newDev) {
1045 SkErrorInternals::SetError(kInternalError_SkError,
1046 "Unable to create device for layer.");
1047 return;
1048 }
1049 forceSpriteOnRestore = true;
1050 }
1051 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001052 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001053
reed@google.com6f8f2922011-03-04 22:27:10 +00001054 device->setOrigin(ir.fLeft, ir.fTop);
reed61f501f2015-04-29 08:34:00 -07001055 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip,
reed86a17e72015-05-14 12:25:22 -07001056 forceSpriteOnRestore));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001057 device->unref();
1058
1059 layer->fNext = fMCRec->fTopLayer;
1060 fMCRec->fLayer = layer;
1061 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062}
1063
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001064int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1065 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1066}
1067
reed@android.com8a1c16f2008-12-17 15:59:43 +00001068int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1069 SaveFlags flags) {
1070 if (0xFF == alpha) {
1071 return this->saveLayer(bounds, NULL, flags);
1072 } else {
1073 SkPaint tmpPaint;
1074 tmpPaint.setAlpha(alpha);
1075 return this->saveLayer(bounds, &tmpPaint, flags);
1076 }
1077}
1078
reed@android.com8a1c16f2008-12-17 15:59:43 +00001079void SkCanvas::internalRestore() {
1080 SkASSERT(fMCStack.count() != 0);
1081
1082 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001083 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001084
reed687fa1c2015-04-07 08:00:56 -07001085 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001086
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001087 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001088 DeviceCM* layer = fMCRec->fLayer; // may be null
1089 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1090 fMCRec->fLayer = NULL;
1091
1092 // now do the normal restore()
1093 fMCRec->~MCRec(); // balanced in save()
1094 fMCStack.pop_back();
1095 fMCRec = (MCRec*)fMCStack.back();
1096
1097 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1098 since if we're being recorded, we don't want to record this (the
1099 recorder will have already recorded the restore).
1100 */
bsalomon49f085d2014-09-05 13:34:00 -07001101 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001102 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001103 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001104 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001105 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001106 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001107 fDeviceCMDirty = true;
reedb679ca82015-04-07 04:40:48 -07001108 SkDELETE(layer);
1109 } else {
1110 // we're at the root
reeda499f902015-05-01 09:34:31 -07001111 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001112 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001113 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001114 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001115}
1116
reed4a8126e2014-09-22 07:29:03 -07001117SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1118 if (NULL == props) {
1119 props = &fProps;
1120 }
1121 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001122}
1123
reed4a8126e2014-09-22 07:29:03 -07001124SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001125 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001126 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001127}
1128
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001129SkImageInfo SkCanvas::imageInfo() const {
1130 SkBaseDevice* dev = this->getDevice();
1131 if (dev) {
1132 return dev->imageInfo();
1133 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001134 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001135 }
1136}
1137
1138const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001139 SkPixmap pmap;
1140 if (!this->onPeekPixels(&pmap)) {
1141 return NULL;
1142 }
1143 if (info) {
1144 *info = pmap.info();
1145 }
1146 if (rowBytes) {
1147 *rowBytes = pmap.rowBytes();
1148 }
1149 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001150}
1151
reed884e97c2015-05-26 11:31:54 -07001152bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001153 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001154 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001155}
1156
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001157void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001158 SkPixmap pmap;
1159 if (!this->onAccessTopLayerPixels(&pmap)) {
1160 return NULL;
1161 }
1162 if (info) {
1163 *info = pmap.info();
1164 }
1165 if (rowBytes) {
1166 *rowBytes = pmap.rowBytes();
1167 }
1168 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001169 *origin = this->getTopDevice(false)->getOrigin();
1170 }
reed884e97c2015-05-26 11:31:54 -07001171 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001172}
1173
reed884e97c2015-05-26 11:31:54 -07001174bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001175 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001176 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001177}
1178
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001179SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1180 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1181 if (NULL == fAddr) {
1182 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001183 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001184 return; // failure, fAddr is NULL
1185 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001186 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1187 return; // failure, fAddr is NULL
1188 }
1189 fAddr = fBitmap.getPixels();
1190 fRowBytes = fBitmap.rowBytes();
1191 }
1192 SkASSERT(fAddr); // success
1193}
1194
1195bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1196 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001197 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001198 } else {
1199 bitmap->reset();
1200 return false;
1201 }
1202}
1203
reed@android.com8a1c16f2008-12-17 15:59:43 +00001204/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001205void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001206 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001207 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001208 return;
1209 }
1210
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001211 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001213 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001214 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001215
1216 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001217
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001218 SkRect storage;
1219 const SkRect* bounds = NULL;
1220 if (paint && paint->canComputeFastBounds()) {
1221 bitmap.getBounds(&storage);
1222 matrix.mapRect(&storage);
1223 bounds = &paint->computeFastBounds(storage, &storage);
1224 }
1225
1226 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001227
1228 while (iter.next()) {
1229 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1230 }
1231
1232 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001233}
1234
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001235void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001236 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001237 SkPaint tmp;
1238 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001239 paint = &tmp;
1240 }
reed@google.com4b226022011-01-11 18:32:13 +00001241
reed@google.com8926b162012-03-23 15:36:36 +00001242 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001243 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001244 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001245 paint = &looper.paint();
1246 SkImageFilter* filter = paint->getImageFilter();
1247 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001248 if (filter && !dstDev->canHandleImageFilter(filter)) {
robertphillipsefbffed2015-06-22 12:06:08 -07001249 SkImageFilter::Proxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001250 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001251 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001252 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001253 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001254 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001255 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001256 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001257 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001258 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001259 SkPaint tmpUnfiltered(*paint);
1260 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001261 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1262 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001263 }
reed61f501f2015-04-29 08:34:00 -07001264 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001265 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001266 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001267 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001268 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001269 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001270 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001271 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001272}
1273
reed41af9662015-01-05 07:49:08 -08001274void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001275 if (gTreatSpriteAsBitmap) {
1276 this->save();
1277 this->resetMatrix();
1278 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1279 this->restore();
1280 return;
1281 }
1282
danakj9881d632014-11-26 12:41:06 -08001283 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001284 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001285 return;
1286 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001287 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001288
reed@google.com8926b162012-03-23 15:36:36 +00001289 SkPaint tmp;
1290 if (NULL == paint) {
1291 paint = &tmp;
1292 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001293
reed@google.com8926b162012-03-23 15:36:36 +00001294 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001295
reed@google.com8926b162012-03-23 15:36:36 +00001296 while (iter.next()) {
1297 paint = &looper.paint();
1298 SkImageFilter* filter = paint->getImageFilter();
1299 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1300 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
robertphillipsefbffed2015-06-22 12:06:08 -07001301 SkImageFilter::Proxy proxy(iter.fDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001302 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001303 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001304 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001305 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001306 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001307 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001308 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001309 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001310 SkPaint tmpUnfiltered(*paint);
1311 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001312 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001313 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001314 }
1315 } else {
1316 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1317 }
1318 }
1319 LOOPER_END
1320}
1321
reed@android.com8a1c16f2008-12-17 15:59:43 +00001322/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001323void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001324 SkMatrix m;
1325 m.setTranslate(dx, dy);
1326 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001327}
1328
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001329void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001330 SkMatrix m;
1331 m.setScale(sx, sy);
1332 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001333}
1334
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001335void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001336 SkMatrix m;
1337 m.setRotate(degrees);
1338 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001339}
1340
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001341void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001342 SkMatrix m;
1343 m.setSkew(sx, sy);
1344 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001345}
1346
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001347void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001348 if (matrix.isIdentity()) {
1349 return;
1350 }
1351
reed2ff1fce2014-12-11 07:07:37 -08001352 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001353 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001354 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001355 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001356
1357 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001358}
1359
reed86a17e72015-05-14 12:25:22 -07001360void SkCanvas::setMatrix(const SkMatrix& matrix) {
1361 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001362 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001363 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001364 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001365 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001366}
1367
reed@android.com8a1c16f2008-12-17 15:59:43 +00001368void SkCanvas::resetMatrix() {
1369 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001370
reed@android.com8a1c16f2008-12-17 15:59:43 +00001371 matrix.reset();
1372 this->setMatrix(matrix);
1373}
1374
1375//////////////////////////////////////////////////////////////////////////////
1376
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001377void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001378 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001379 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1380 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001381}
1382
1383void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001384#ifdef SK_ENABLE_CLIP_QUICKREJECT
1385 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001386 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001387 return false;
1388 }
1389
reed@google.com3b3e8952012-08-16 20:53:31 +00001390 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001391 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001392 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001393
reed687fa1c2015-04-07 08:00:56 -07001394 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001395 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001396 }
1397 }
1398#endif
1399
reed@google.com5c3d1472011-02-22 19:12:23 +00001400 AutoValidateClip avc(this);
1401
reed@android.com8a1c16f2008-12-17 15:59:43 +00001402 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001403 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001404 if (!fAllowSoftClip) {
1405 edgeStyle = kHard_ClipEdgeStyle;
1406 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001407
reed1f836ee2014-07-07 07:49:34 -07001408 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001409 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001410 // the matrix. This means we don't have to a) make a path, and b) tell
1411 // the region code to scan-convert the path, only to discover that it
1412 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001413 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414
reed1f836ee2014-07-07 07:49:34 -07001415 fMCRec->fMatrix.mapRect(&r, rect);
reed687fa1c2015-04-07 08:00:56 -07001416 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001417 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001418 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001419 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001420 // and clip against that, since it can handle any matrix. However, to
1421 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1422 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001423 SkPath path;
1424
1425 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001426 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001427 }
1428}
1429
reed73e714e2014-09-04 09:02:23 -07001430static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1431 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001432 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001433}
1434
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001435void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001436 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001437 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001438 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001439 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1440 } else {
1441 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001442 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001443}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001444
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001445void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001446 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001447 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001448 AutoValidateClip avc(this);
1449
1450 fDeviceCMDirty = true;
1451 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001452 if (!fAllowSoftClip) {
1453 edgeStyle = kHard_ClipEdgeStyle;
1454 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001455
reed687fa1c2015-04-07 08:00:56 -07001456 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001457
1458 SkPath devPath;
1459 devPath.addRRect(transformedRRect);
1460
reed73e714e2014-09-04 09:02:23 -07001461 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001462 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001463 }
1464
1465 SkPath path;
1466 path.addRRect(rrect);
1467 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001468 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001469}
1470
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001471void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001472 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001473 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1474 SkRect r;
1475 if (!path.isInverseFillType() && path.isRect(&r)) {
1476 this->onClipRect(r, op, edgeStyle);
1477 } else {
1478 this->onClipPath(path, op, edgeStyle);
1479 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001480}
1481
1482void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001483#ifdef SK_ENABLE_CLIP_QUICKREJECT
1484 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001485 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001486 return false;
1487 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001488
reed@google.com3b3e8952012-08-16 20:53:31 +00001489 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001490 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001491 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001492
reed687fa1c2015-04-07 08:00:56 -07001493 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001494 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001495 }
1496 }
1497#endif
1498
reed@google.com5c3d1472011-02-22 19:12:23 +00001499 AutoValidateClip avc(this);
1500
reed@android.com8a1c16f2008-12-17 15:59:43 +00001501 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001502 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001503 if (!fAllowSoftClip) {
1504 edgeStyle = kHard_ClipEdgeStyle;
1505 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001506
1507 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001508 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001509
reed@google.comfe701122011-11-08 19:41:23 +00001510 // Check if the transfomation, or the original path itself
1511 // made us empty. Note this can also happen if we contained NaN
1512 // values. computing the bounds detects this, and will set our
1513 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1514 if (devPath.getBounds().isEmpty()) {
1515 // resetting the path will remove any NaN or other wanky values
1516 // that might upset our scan converter.
1517 devPath.reset();
1518 }
1519
reed@google.com5c3d1472011-02-22 19:12:23 +00001520 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001521 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001522
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001523 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001524 bool clipIsAA = getClipStack()->asPath(&devPath);
1525 if (clipIsAA) {
1526 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001527 }
fmalita1a481fe2015-02-04 07:39:34 -08001528
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001529 op = SkRegion::kReplace_Op;
1530 }
1531
reed73e714e2014-09-04 09:02:23 -07001532 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001533}
1534
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001535void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001536 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001537 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001538}
1539
1540void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001541 AutoValidateClip avc(this);
1542
reed@android.com8a1c16f2008-12-17 15:59:43 +00001543 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001544 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001545
reed@google.com5c3d1472011-02-22 19:12:23 +00001546 // todo: signal fClipStack that we have a region, and therefore (I guess)
1547 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001548 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001549
reed1f836ee2014-07-07 07:49:34 -07001550 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001551}
1552
reed@google.com819c9212011-02-23 18:56:55 +00001553#ifdef SK_DEBUG
1554void SkCanvas::validateClip() const {
1555 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001556 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001557 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001558 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001559 return;
1560 }
1561
reed@google.com819c9212011-02-23 18:56:55 +00001562 SkIRect ir;
1563 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001564 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001565
reed687fa1c2015-04-07 08:00:56 -07001566 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001567 const SkClipStack::Element* element;
1568 while ((element = iter.next()) != NULL) {
1569 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001570 case SkClipStack::Element::kRect_Type:
1571 element->getRect().round(&ir);
1572 tmpClip.op(ir, element->getOp());
1573 break;
1574 case SkClipStack::Element::kEmpty_Type:
1575 tmpClip.setEmpty();
1576 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001577 default: {
1578 SkPath path;
1579 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001580 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001581 break;
1582 }
reed@google.com819c9212011-02-23 18:56:55 +00001583 }
1584 }
reed@google.com819c9212011-02-23 18:56:55 +00001585}
1586#endif
1587
reed@google.com90c07ea2012-04-13 13:50:27 +00001588void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001589 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001590 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001591
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001592 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001593 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001594 }
1595}
1596
reed@google.com5c3d1472011-02-22 19:12:23 +00001597///////////////////////////////////////////////////////////////////////////////
1598
reed@google.com754de5f2014-02-24 19:38:20 +00001599bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001600 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001601}
1602
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001603bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001604 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001605}
1606
reed@google.com3b3e8952012-08-16 20:53:31 +00001607bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001608 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001609 return true;
1610
reed1f836ee2014-07-07 07:49:34 -07001611 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001612 return true;
1613 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001614
reed1f836ee2014-07-07 07:49:34 -07001615 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001616 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001617 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001618 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001619 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001620 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001621
reed@android.coma380ae42009-07-21 01:17:02 +00001622 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001623 // TODO: should we use | instead, or compare all 4 at once?
1624 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001625 return true;
1626 }
reed@google.comc0784db2013-12-13 21:16:12 +00001627 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001628 return true;
1629 }
1630 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001631 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001632}
1633
reed@google.com3b3e8952012-08-16 20:53:31 +00001634bool SkCanvas::quickReject(const SkPath& path) const {
1635 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001636}
1637
reed@google.com3b3e8952012-08-16 20:53:31 +00001638bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001639 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001640 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001641 return false;
1642 }
1643
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001644 SkMatrix inverse;
1645 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001646 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001647 if (bounds) {
1648 bounds->setEmpty();
1649 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001650 return false;
1651 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001652
bsalomon49f085d2014-09-05 13:34:00 -07001653 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001654 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001655 // adjust it outwards in case we are antialiasing
1656 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001657
reed@google.com8f4d2302013-12-17 16:44:46 +00001658 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1659 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001660 inverse.mapRect(bounds, r);
1661 }
1662 return true;
1663}
1664
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001665bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001666 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001667 if (clip.isEmpty()) {
1668 if (bounds) {
1669 bounds->setEmpty();
1670 }
1671 return false;
1672 }
1673
bsalomon49f085d2014-09-05 13:34:00 -07001674 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001675 *bounds = clip.getBounds();
1676 }
1677 return true;
1678}
1679
reed@android.com8a1c16f2008-12-17 15:59:43 +00001680const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001681 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001682}
1683
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001684const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001685 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001686}
1687
reed@google.com9c135db2014-03-12 18:28:35 +00001688GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1689 SkBaseDevice* dev = this->getTopDevice();
1690 return dev ? dev->accessRenderTarget() : NULL;
1691}
1692
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001693GrContext* SkCanvas::getGrContext() {
1694#if SK_SUPPORT_GPU
1695 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001696 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001697 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001698 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001699 return renderTarget->getContext();
1700 }
1701 }
1702#endif
1703
1704 return NULL;
1705
1706}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001707
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001708void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1709 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001710 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001711 if (outer.isEmpty()) {
1712 return;
1713 }
1714 if (inner.isEmpty()) {
1715 this->drawRRect(outer, paint);
1716 return;
1717 }
1718
1719 // We don't have this method (yet), but technically this is what we should
1720 // be able to assert...
1721 // SkASSERT(outer.contains(inner));
1722 //
1723 // For now at least check for containment of bounds
1724 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1725
1726 this->onDrawDRRect(outer, inner, paint);
1727}
1728
reed41af9662015-01-05 07:49:08 -08001729// These need to stop being virtual -- clients need to override the onDraw... versions
1730
1731void SkCanvas::drawPaint(const SkPaint& paint) {
1732 this->onDrawPaint(paint);
1733}
1734
1735void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1736 this->onDrawRect(r, paint);
1737}
1738
1739void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1740 this->onDrawOval(r, paint);
1741}
1742
1743void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1744 this->onDrawRRect(rrect, paint);
1745}
1746
1747void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1748 this->onDrawPoints(mode, count, pts, paint);
1749}
1750
1751void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1752 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1753 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1754 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1755 indices, indexCount, paint);
1756}
1757
1758void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1759 this->onDrawPath(path, paint);
1760}
1761
reeda85d4d02015-05-06 12:56:48 -07001762void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1763 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001764}
1765
1766void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1767 const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07001768 if (dst.isEmpty()) {
1769 return;
1770 }
reed41af9662015-01-05 07:49:08 -08001771 this->onDrawImageRect(image, src, dst, paint);
1772}
1773
1774void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001775 if (bitmap.empty()) {
1776 return;
1777 }
reed41af9662015-01-05 07:49:08 -08001778 this->onDrawBitmap(bitmap, dx, dy, paint);
1779}
1780
1781void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1782 const SkPaint* paint, DrawBitmapRectFlags flags) {
tomhudson2df6fd62015-04-09 09:20:19 -07001783 if (bitmap.empty()) {
1784 return;
1785 }
reed41af9662015-01-05 07:49:08 -08001786 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1787}
1788
1789void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1790 const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001791 if (bitmap.empty()) {
1792 return;
1793 }
reed41af9662015-01-05 07:49:08 -08001794 this->onDrawBitmapNine(bitmap, center, dst, paint);
1795}
1796
1797void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001798 if (bitmap.empty()) {
1799 return;
1800 }
reed41af9662015-01-05 07:49:08 -08001801 this->onDrawSprite(bitmap, left, top, paint);
1802}
1803
reed@android.com8a1c16f2008-12-17 15:59:43 +00001804//////////////////////////////////////////////////////////////////////////////
1805// These are the virtual drawing methods
1806//////////////////////////////////////////////////////////////////////////////
1807
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001808void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001809 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001810 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1811 }
1812}
1813
reed41af9662015-01-05 07:49:08 -08001814void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001815 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001816 this->internalDrawPaint(paint);
1817}
1818
1819void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001820 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001821
1822 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001823 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001824 }
1825
reed@google.com4e2b3d32011-04-07 14:18:59 +00001826 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001827}
1828
reed41af9662015-01-05 07:49:08 -08001829void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1830 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001831 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001832 if ((long)count <= 0) {
1833 return;
1834 }
1835
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001836 SkRect r, storage;
1837 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001838 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001839 // special-case 2 points (common for drawing a single line)
1840 if (2 == count) {
1841 r.set(pts[0], pts[1]);
1842 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001843 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001844 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001845 bounds = &paint.computeFastStrokeBounds(r, &storage);
1846 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001847 return;
1848 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001849 }
reed@google.coma584aed2012-05-16 14:06:02 +00001850
reed@android.com8a1c16f2008-12-17 15:59:43 +00001851 SkASSERT(pts != NULL);
1852
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001853 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001854
reed@android.com8a1c16f2008-12-17 15:59:43 +00001855 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001856 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001857 }
reed@google.com4b226022011-01-11 18:32:13 +00001858
reed@google.com4e2b3d32011-04-07 14:18:59 +00001859 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001860}
1861
reed41af9662015-01-05 07:49:08 -08001862void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001863 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001864 SkRect storage;
1865 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001866 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001867 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1868 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1869 SkRect tmp(r);
1870 tmp.sort();
1871
1872 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001873 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001874 return;
1875 }
1876 }
reed@google.com4b226022011-01-11 18:32:13 +00001877
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001878 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001879
1880 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001881 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001882 }
1883
reed@google.com4e2b3d32011-04-07 14:18:59 +00001884 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001885}
1886
reed41af9662015-01-05 07:49:08 -08001887void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001888 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001889 SkRect storage;
1890 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001891 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001892 bounds = &paint.computeFastBounds(oval, &storage);
1893 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001894 return;
1895 }
1896 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001897
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001898 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001899
1900 while (iter.next()) {
1901 iter.fDevice->drawOval(iter, oval, looper.paint());
1902 }
1903
1904 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001905}
1906
reed41af9662015-01-05 07:49:08 -08001907void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001908 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001909 SkRect storage;
1910 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001911 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001912 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1913 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001914 return;
1915 }
1916 }
1917
1918 if (rrect.isRect()) {
1919 // call the non-virtual version
1920 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001921 return;
1922 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001923 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001924 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1925 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001926 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001927
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001928 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001929
1930 while (iter.next()) {
1931 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1932 }
1933
1934 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001935}
1936
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001937void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1938 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001939 SkRect storage;
1940 const SkRect* bounds = NULL;
1941 if (paint.canComputeFastBounds()) {
1942 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1943 if (this->quickReject(*bounds)) {
1944 return;
1945 }
1946 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001947
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001948 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001949
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001950 while (iter.next()) {
1951 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1952 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001953
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001954 LOOPER_END
1955}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001956
reed41af9662015-01-05 07:49:08 -08001957void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001958 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001959 if (!path.isFinite()) {
1960 return;
1961 }
1962
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001963 SkRect storage;
1964 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001965 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001966 const SkRect& pathBounds = path.getBounds();
1967 bounds = &paint.computeFastBounds(pathBounds, &storage);
1968 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001969 return;
1970 }
1971 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001972
1973 const SkRect& r = path.getBounds();
1974 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001975 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001976 this->internalDrawPaint(paint);
1977 }
1978 return;
1979 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001980
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001981 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001982
1983 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001984 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001985 }
1986
reed@google.com4e2b3d32011-04-07 14:18:59 +00001987 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001988}
1989
reeda85d4d02015-05-06 12:56:48 -07001990void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001991 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07001992 SkRect bounds = SkRect::MakeXYWH(x, y,
1993 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
1994 if (NULL == paint || paint->canComputeFastBounds()) {
1995 if (paint) {
1996 paint->computeFastBounds(bounds, &bounds);
1997 }
1998 if (this->quickReject(bounds)) {
1999 return;
2000 }
2001 }
2002
2003 SkLazyPaint lazy;
2004 if (NULL == paint) {
2005 paint = lazy.init();
2006 }
2007
2008 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds)
2009
2010 while (iter.next()) {
2011 iter.fDevice->drawImage(iter, image, x, y, looper.paint());
2012 }
2013
2014 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002015}
2016
reed41af9662015-01-05 07:49:08 -08002017void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2018 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002019 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
reeda85d4d02015-05-06 12:56:48 -07002020 SkRect storage;
2021 const SkRect* bounds = &dst;
2022 if (NULL == paint || paint->canComputeFastBounds()) {
2023 if (paint) {
2024 bounds = &paint->computeFastBounds(dst, &storage);
2025 }
2026 if (this->quickReject(*bounds)) {
2027 return;
2028 }
2029 }
2030 SkLazyPaint lazy;
2031 if (NULL == paint) {
2032 paint = lazy.init();
2033 }
2034
2035 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2036
2037 while (iter.next()) {
2038 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint());
2039 }
2040
2041 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002042}
2043
reed41af9662015-01-05 07:49:08 -08002044void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002045 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002046 SkDEBUGCODE(bitmap.validate();)
2047
reed@google.com3d608122011-11-21 15:16:16 +00002048 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002049 SkRect bounds = {
2050 x, y,
2051 x + SkIntToScalar(bitmap.width()),
2052 y + SkIntToScalar(bitmap.height())
2053 };
2054 if (paint) {
2055 (void)paint->computeFastBounds(bounds, &bounds);
2056 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002057 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002058 return;
2059 }
2060 }
reed@google.com4b226022011-01-11 18:32:13 +00002061
reed@android.com8a1c16f2008-12-17 15:59:43 +00002062 SkMatrix matrix;
2063 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00002064 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002065}
2066
reed@google.com9987ec32011-09-07 11:57:52 +00002067// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002068void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002069 const SkRect& dst, const SkPaint* paint,
2070 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002071 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002072 return;
2073 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002074
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002075 SkRect storage;
2076 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00002077 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002078 if (paint) {
2079 bounds = &paint->computeFastBounds(dst, &storage);
2080 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002081 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002082 return;
2083 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002084 }
reed@google.com3d608122011-11-21 15:16:16 +00002085
reed@google.com33535f32012-09-25 15:37:50 +00002086 SkLazyPaint lazy;
2087 if (NULL == paint) {
2088 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002089 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002090
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002091 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002092
reed@google.com33535f32012-09-25 15:37:50 +00002093 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002094 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00002095 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002096
reed@google.com33535f32012-09-25 15:37:50 +00002097 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002098}
2099
reed41af9662015-01-05 07:49:08 -08002100void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2101 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08002102 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002103 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002104 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00002105}
2106
reed@google.com9987ec32011-09-07 11:57:52 +00002107void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
2108 const SkIRect& center, const SkRect& dst,
2109 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002110 if (bitmap.drawsNothing()) {
2111 return;
2112 }
reed@google.com3d608122011-11-21 15:16:16 +00002113 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00002114 SkRect storage;
2115 const SkRect* bounds = &dst;
2116 if (paint) {
2117 bounds = &paint->computeFastBounds(dst, &storage);
2118 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002119 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002120 return;
2121 }
2122 }
2123
reed@google.com9987ec32011-09-07 11:57:52 +00002124 const int32_t w = bitmap.width();
2125 const int32_t h = bitmap.height();
2126
2127 SkIRect c = center;
2128 // pin center to the bounds of the bitmap
2129 c.fLeft = SkMax32(0, center.fLeft);
2130 c.fTop = SkMax32(0, center.fTop);
2131 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2132 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2133
reed@google.com71121732012-09-18 15:14:33 +00002134 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002135 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00002136 };
2137 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002138 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00002139 };
reed@google.com9987ec32011-09-07 11:57:52 +00002140 SkScalar dstX[4] = {
2141 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2142 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2143 };
2144 SkScalar dstY[4] = {
2145 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2146 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2147 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002148
reed@google.com9987ec32011-09-07 11:57:52 +00002149 if (dstX[1] > dstX[2]) {
2150 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2151 dstX[2] = dstX[1];
2152 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002153
reed@google.com9987ec32011-09-07 11:57:52 +00002154 if (dstY[1] > dstY[2]) {
2155 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2156 dstY[2] = dstY[1];
2157 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002158
reed@google.com9987ec32011-09-07 11:57:52 +00002159 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00002160 SkRect s, d;
2161
reed@google.com9987ec32011-09-07 11:57:52 +00002162 s.fTop = srcY[y];
2163 s.fBottom = srcY[y+1];
2164 d.fTop = dstY[y];
2165 d.fBottom = dstY[y+1];
2166 for (int x = 0; x < 3; x++) {
2167 s.fLeft = srcX[x];
2168 s.fRight = srcX[x+1];
2169 d.fLeft = dstX[x];
2170 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002171 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00002172 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00002173 }
2174 }
2175}
2176
reed41af9662015-01-05 07:49:08 -08002177void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2178 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002179 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002180 SkDEBUGCODE(bitmap.validate();)
2181
2182 // Need a device entry-point, so gpu can use a mesh
2183 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2184}
2185
reed@google.comf67e4cf2011-03-15 20:56:58 +00002186class SkDeviceFilteredPaint {
2187public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002188 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002189 uint32_t filteredFlags = device->filterTextFlags(paint);
2190 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002191 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002192 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002193 fPaint = newPaint;
2194 } else {
2195 fPaint = &paint;
2196 }
2197 }
2198
reed@google.comf67e4cf2011-03-15 20:56:58 +00002199 const SkPaint& paint() const { return *fPaint; }
2200
2201private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002202 const SkPaint* fPaint;
2203 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002204};
2205
bungeman@google.com52c748b2011-08-22 21:30:43 +00002206void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2207 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002208 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002209 draw.fDevice->drawRect(draw, r, paint);
2210 } else {
2211 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002212 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002213 draw.fDevice->drawRect(draw, r, p);
2214 }
2215}
2216
2217void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2218 const char text[], size_t byteLength,
2219 SkScalar x, SkScalar y) {
2220 SkASSERT(byteLength == 0 || text != NULL);
2221
2222 // nothing to draw
2223 if (text == NULL || byteLength == 0 ||
2224 draw.fClip->isEmpty() ||
2225 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2226 return;
2227 }
2228
2229 SkScalar width = 0;
2230 SkPoint start;
2231
2232 start.set(0, 0); // to avoid warning
2233 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2234 SkPaint::kStrikeThruText_Flag)) {
2235 width = paint.measureText(text, byteLength);
2236
2237 SkScalar offsetX = 0;
2238 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2239 offsetX = SkScalarHalf(width);
2240 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2241 offsetX = width;
2242 }
2243 start.set(x - offsetX, y);
2244 }
2245
2246 if (0 == width) {
2247 return;
2248 }
2249
2250 uint32_t flags = paint.getFlags();
2251
2252 if (flags & (SkPaint::kUnderlineText_Flag |
2253 SkPaint::kStrikeThruText_Flag)) {
2254 SkScalar textSize = paint.getTextSize();
2255 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2256 SkRect r;
2257
2258 r.fLeft = start.fX;
2259 r.fRight = start.fX + width;
2260
2261 if (flags & SkPaint::kUnderlineText_Flag) {
2262 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2263 start.fY);
2264 r.fTop = offset;
2265 r.fBottom = offset + height;
2266 DrawRect(draw, paint, r, textSize);
2267 }
2268 if (flags & SkPaint::kStrikeThruText_Flag) {
2269 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2270 start.fY);
2271 r.fTop = offset;
2272 r.fBottom = offset + height;
2273 DrawRect(draw, paint, r, textSize);
2274 }
2275 }
2276}
2277
reed@google.come0d9ce82014-04-23 04:00:17 +00002278void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2279 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002280 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002281
2282 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002283 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002284 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002285 DrawTextDecorations(iter, dfp.paint(),
2286 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002287 }
2288
reed@google.com4e2b3d32011-04-07 14:18:59 +00002289 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002290}
2291
reed@google.come0d9ce82014-04-23 04:00:17 +00002292void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2293 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002294 SkPoint textOffset = SkPoint::Make(0, 0);
2295
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002296 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002297
reed@android.com8a1c16f2008-12-17 15:59:43 +00002298 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002299 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002300 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002301 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002303
reed@google.com4e2b3d32011-04-07 14:18:59 +00002304 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305}
2306
reed@google.come0d9ce82014-04-23 04:00:17 +00002307void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2308 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002309
2310 SkPoint textOffset = SkPoint::Make(0, constY);
2311
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002312 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002313
reed@android.com8a1c16f2008-12-17 15:59:43 +00002314 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002315 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002316 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002317 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002319
reed@google.com4e2b3d32011-04-07 14:18:59 +00002320 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002321}
2322
reed@google.come0d9ce82014-04-23 04:00:17 +00002323void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2324 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002325 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002326
reed@android.com8a1c16f2008-12-17 15:59:43 +00002327 while (iter.next()) {
2328 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002329 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002330 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002331
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002332 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002333}
2334
fmalita00d5c2c2014-08-21 08:53:26 -07002335void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2336 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002337
fmalita85d5eb92015-03-04 11:20:12 -08002338 SkRect storage;
2339 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002340 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002341 storage = blob->bounds().makeOffset(x, y);
2342 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002343
fmalita85d5eb92015-03-04 11:20:12 -08002344 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002345 return;
2346 }
2347 }
2348
fmalita024f9962015-03-03 19:08:17 -08002349 // We cannot filter in the looper as we normally do, because the paint is
2350 // incomplete at this point (text-related attributes are embedded within blob run paints).
2351 SkDrawFilter* drawFilter = fMCRec->fFilter;
2352 fMCRec->fFilter = NULL;
2353
fmalita85d5eb92015-03-04 11:20:12 -08002354 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002355
fmalitaaa1b9122014-08-28 14:32:24 -07002356 while (iter.next()) {
2357 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002358 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002359 }
2360
fmalitaaa1b9122014-08-28 14:32:24 -07002361 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002362
2363 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002364}
2365
reed@google.come0d9ce82014-04-23 04:00:17 +00002366// These will become non-virtual, so they always call the (virtual) onDraw... method
2367void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2368 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002369 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002370 this->onDrawText(text, byteLength, x, y, paint);
2371}
2372void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2373 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002374 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002375 this->onDrawPosText(text, byteLength, pos, paint);
2376}
2377void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2378 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002379 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002380 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2381}
2382void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2383 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002384 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002385 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2386}
fmalita00d5c2c2014-08-21 08:53:26 -07002387void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2388 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002389 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002390 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002391 this->onDrawTextBlob(blob, x, y, paint);
2392 }
2393}
reed@google.come0d9ce82014-04-23 04:00:17 +00002394
reed41af9662015-01-05 07:49:08 -08002395void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2396 const SkPoint verts[], const SkPoint texs[],
2397 const SkColor colors[], SkXfermode* xmode,
2398 const uint16_t indices[], int indexCount,
2399 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002400 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002401 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002402
reed@android.com8a1c16f2008-12-17 15:59:43 +00002403 while (iter.next()) {
2404 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002405 colors, xmode, indices, indexCount,
2406 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002407 }
reed@google.com4b226022011-01-11 18:32:13 +00002408
reed@google.com4e2b3d32011-04-07 14:18:59 +00002409 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002410}
2411
dandovb3c9d1c2014-08-12 08:34:29 -07002412void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2413 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002414 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002415 if (NULL == cubics) {
2416 return;
2417 }
mtklein6cfa73a2014-08-13 13:33:49 -07002418
dandovecfff212014-08-04 10:02:00 -07002419 // Since a patch is always within the convex hull of the control points, we discard it when its
2420 // bounding rectangle is completely outside the current clip.
2421 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002422 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002423 if (this->quickReject(bounds)) {
2424 return;
2425 }
mtklein6cfa73a2014-08-13 13:33:49 -07002426
dandovb3c9d1c2014-08-12 08:34:29 -07002427 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2428}
2429
2430void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2431 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2432
dandovecfff212014-08-04 10:02:00 -07002433 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002434
dandovecfff212014-08-04 10:02:00 -07002435 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002436 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002437 }
mtklein6cfa73a2014-08-13 13:33:49 -07002438
dandovecfff212014-08-04 10:02:00 -07002439 LOOPER_END
2440}
2441
reed3cb38402015-02-06 08:36:15 -08002442void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002443 if (dr && !this->quickReject(dr->getBounds())) {
2444 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002445 }
2446}
2447
reed3cb38402015-02-06 08:36:15 -08002448void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002449 dr->draw(this);
2450}
2451
reed@android.com8a1c16f2008-12-17 15:59:43 +00002452//////////////////////////////////////////////////////////////////////////////
2453// These methods are NOT virtual, and therefore must call back into virtual
2454// methods, rather than actually drawing themselves.
2455//////////////////////////////////////////////////////////////////////////////
2456
2457void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002458 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002459 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002460 SkPaint paint;
2461
2462 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002463 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002464 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002465 }
2466 this->drawPaint(paint);
2467}
2468
reed@android.com845fdac2009-06-23 03:01:32 +00002469void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002470 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002471 SkPaint paint;
2472
2473 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002474 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002475 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002476 }
2477 this->drawPaint(paint);
2478}
2479
2480void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002481 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002482 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002483
reed@android.com8a1c16f2008-12-17 15:59:43 +00002484 pt.set(x, y);
2485 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2486}
2487
2488void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002489 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002490 SkPoint pt;
2491 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002492
reed@android.com8a1c16f2008-12-17 15:59:43 +00002493 pt.set(x, y);
2494 paint.setColor(color);
2495 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2496}
2497
2498void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2499 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002500 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002501 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002502
reed@android.com8a1c16f2008-12-17 15:59:43 +00002503 pts[0].set(x0, y0);
2504 pts[1].set(x1, y1);
2505 this->drawPoints(kLines_PointMode, 2, pts, paint);
2506}
2507
2508void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2509 SkScalar right, SkScalar bottom,
2510 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002511 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002512 SkRect r;
2513
2514 r.set(left, top, right, bottom);
2515 this->drawRect(r, paint);
2516}
2517
2518void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2519 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002520 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002521 if (radius < 0) {
2522 radius = 0;
2523 }
2524
2525 SkRect r;
2526 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002527 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002528}
2529
2530void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2531 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002532 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002533 if (rx > 0 && ry > 0) {
2534 if (paint.canComputeFastBounds()) {
2535 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002536 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002537 return;
2538 }
2539 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002540 SkRRect rrect;
2541 rrect.setRectXY(r, rx, ry);
2542 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002543 } else {
2544 this->drawRect(r, paint);
2545 }
2546}
2547
reed@android.com8a1c16f2008-12-17 15:59:43 +00002548void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2549 SkScalar sweepAngle, bool useCenter,
2550 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002551 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002552 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2553 this->drawOval(oval, paint);
2554 } else {
2555 SkPath path;
2556 if (useCenter) {
2557 path.moveTo(oval.centerX(), oval.centerY());
2558 }
2559 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2560 if (useCenter) {
2561 path.close();
2562 }
2563 this->drawPath(path, paint);
2564 }
2565}
2566
2567void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2568 const SkPath& path, SkScalar hOffset,
2569 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002570 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002571 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002572
reed@android.com8a1c16f2008-12-17 15:59:43 +00002573 matrix.setTranslate(hOffset, vOffset);
2574 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2575}
2576
reed@android.comf76bacf2009-05-13 14:00:33 +00002577///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002578
2579/**
2580 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2581 * against the playback cost of recursing into the subpicture to get at its actual ops.
2582 *
2583 * For now we pick a conservatively small value, though measurement (and other heuristics like
2584 * the type of ops contained) may justify changing this value.
2585 */
2586#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002587
reedd5fa1a42014-08-09 11:08:05 -07002588void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002589 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002590 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002591 if (matrix && matrix->isIdentity()) {
2592 matrix = NULL;
2593 }
reed1c2c4412015-04-30 13:09:24 -07002594 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2595 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2596 picture->playback(this);
2597 } else {
2598 this->onDrawPicture(picture, matrix, paint);
2599 }
reedd5fa1a42014-08-09 11:08:05 -07002600 }
2601}
robertphillips9b14f262014-06-04 05:40:44 -07002602
reedd5fa1a42014-08-09 11:08:05 -07002603void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2604 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002605 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002606 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002607 // Canvas has to first give the device the opportunity to render
2608 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002609 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002610 return; // the device has rendered the entire picture
2611 }
2612 }
2613
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002614 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002615 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002616}
2617
reed@android.com8a1c16f2008-12-17 15:59:43 +00002618///////////////////////////////////////////////////////////////////////////////
2619///////////////////////////////////////////////////////////////////////////////
2620
2621SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002622 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002623
2624 SkASSERT(canvas);
2625
2626 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2627 fDone = !fImpl->next();
2628}
2629
2630SkCanvas::LayerIter::~LayerIter() {
2631 fImpl->~SkDrawIter();
2632}
2633
2634void SkCanvas::LayerIter::next() {
2635 fDone = !fImpl->next();
2636}
2637
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002638SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002639 return fImpl->getDevice();
2640}
2641
2642const SkMatrix& SkCanvas::LayerIter::matrix() const {
2643 return fImpl->getMatrix();
2644}
2645
2646const SkPaint& SkCanvas::LayerIter::paint() const {
2647 const SkPaint* paint = fImpl->getPaint();
2648 if (NULL == paint) {
2649 paint = &fDefaultPaint;
2650 }
2651 return *paint;
2652}
2653
2654const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2655int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2656int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002657
2658///////////////////////////////////////////////////////////////////////////////
2659
fmalitac3b589a2014-06-05 12:40:07 -07002660SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002661
2662///////////////////////////////////////////////////////////////////////////////
2663
2664static bool supported_for_raster_canvas(const SkImageInfo& info) {
2665 switch (info.alphaType()) {
2666 case kPremul_SkAlphaType:
2667 case kOpaque_SkAlphaType:
2668 break;
2669 default:
2670 return false;
2671 }
2672
2673 switch (info.colorType()) {
2674 case kAlpha_8_SkColorType:
2675 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002676 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002677 break;
2678 default:
2679 return false;
2680 }
2681
2682 return true;
2683}
2684
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002685SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2686 if (!supported_for_raster_canvas(info)) {
2687 return NULL;
2688 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002689
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002690 SkBitmap bitmap;
2691 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2692 return NULL;
2693 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002694 return SkNEW_ARGS(SkCanvas, (bitmap));
2695}
reedd5fa1a42014-08-09 11:08:05 -07002696
2697///////////////////////////////////////////////////////////////////////////////
2698
2699SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002700 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002701 : fCanvas(canvas)
2702 , fSaveCount(canvas->getSaveCount())
2703{
bsalomon49f085d2014-09-05 13:34:00 -07002704 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002705 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002706 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002707 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002708 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002709 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002710 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002711 canvas->save();
2712 }
mtklein6cfa73a2014-08-13 13:33:49 -07002713
bsalomon49f085d2014-09-05 13:34:00 -07002714 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002715 canvas->concat(*matrix);
2716 }
2717}
2718
2719SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2720 fCanvas->restoreToCount(fSaveCount);
2721}