blob: d7c62e8e1133ad23e5efd7931dda6e6408dc14ed [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
reed71c3c762015-06-24 10:29:17 -07001804void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1805 const SkColor colors[], int count, SkXfermode::Mode mode,
1806 const SkRect* cull, const SkPaint* paint) {
1807 if (count <= 0) {
1808 return;
1809 }
1810 SkASSERT(atlas);
1811 SkASSERT(xform);
1812 SkASSERT(tex);
1813 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1814}
1815
reed@android.com8a1c16f2008-12-17 15:59:43 +00001816//////////////////////////////////////////////////////////////////////////////
1817// These are the virtual drawing methods
1818//////////////////////////////////////////////////////////////////////////////
1819
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001820void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001821 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001822 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1823 }
1824}
1825
reed41af9662015-01-05 07:49:08 -08001826void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001827 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001828 this->internalDrawPaint(paint);
1829}
1830
1831void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001832 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001833
1834 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001835 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001836 }
1837
reed@google.com4e2b3d32011-04-07 14:18:59 +00001838 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001839}
1840
reed41af9662015-01-05 07:49:08 -08001841void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1842 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001843 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001844 if ((long)count <= 0) {
1845 return;
1846 }
1847
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001848 SkRect r, storage;
1849 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001850 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001851 // special-case 2 points (common for drawing a single line)
1852 if (2 == count) {
1853 r.set(pts[0], pts[1]);
1854 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001855 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001856 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001857 bounds = &paint.computeFastStrokeBounds(r, &storage);
1858 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001859 return;
1860 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001861 }
reed@google.coma584aed2012-05-16 14:06:02 +00001862
reed@android.com8a1c16f2008-12-17 15:59:43 +00001863 SkASSERT(pts != NULL);
1864
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001865 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001866
reed@android.com8a1c16f2008-12-17 15:59:43 +00001867 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001868 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001869 }
reed@google.com4b226022011-01-11 18:32:13 +00001870
reed@google.com4e2b3d32011-04-07 14:18:59 +00001871 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001872}
1873
reed41af9662015-01-05 07:49:08 -08001874void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001875 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001876 SkRect storage;
1877 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001878 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001879 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1880 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1881 SkRect tmp(r);
1882 tmp.sort();
1883
1884 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001885 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001886 return;
1887 }
1888 }
reed@google.com4b226022011-01-11 18:32:13 +00001889
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001890 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001891
1892 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001893 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001894 }
1895
reed@google.com4e2b3d32011-04-07 14:18:59 +00001896 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001897}
1898
reed41af9662015-01-05 07:49:08 -08001899void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001900 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001901 SkRect storage;
1902 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001903 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001904 bounds = &paint.computeFastBounds(oval, &storage);
1905 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001906 return;
1907 }
1908 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001909
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001910 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001911
1912 while (iter.next()) {
1913 iter.fDevice->drawOval(iter, oval, looper.paint());
1914 }
1915
1916 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001917}
1918
reed41af9662015-01-05 07:49:08 -08001919void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001920 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001921 SkRect storage;
1922 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001923 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001924 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1925 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001926 return;
1927 }
1928 }
1929
1930 if (rrect.isRect()) {
1931 // call the non-virtual version
1932 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001933 return;
1934 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001935 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001936 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1937 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001938 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001939
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001940 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001941
1942 while (iter.next()) {
1943 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1944 }
1945
1946 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001947}
1948
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001949void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1950 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001951 SkRect storage;
1952 const SkRect* bounds = NULL;
1953 if (paint.canComputeFastBounds()) {
1954 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1955 if (this->quickReject(*bounds)) {
1956 return;
1957 }
1958 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001959
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001960 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001961
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001962 while (iter.next()) {
1963 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1964 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001965
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001966 LOOPER_END
1967}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001968
reed41af9662015-01-05 07:49:08 -08001969void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001970 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001971 if (!path.isFinite()) {
1972 return;
1973 }
1974
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001975 SkRect storage;
1976 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001977 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001978 const SkRect& pathBounds = path.getBounds();
1979 bounds = &paint.computeFastBounds(pathBounds, &storage);
1980 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001981 return;
1982 }
1983 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001984
1985 const SkRect& r = path.getBounds();
1986 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001987 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001988 this->internalDrawPaint(paint);
1989 }
1990 return;
1991 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001992
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001993 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001994
1995 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001996 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001997 }
1998
reed@google.com4e2b3d32011-04-07 14:18:59 +00001999 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002000}
2001
reeda85d4d02015-05-06 12:56:48 -07002002void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002003 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002004 SkRect bounds = SkRect::MakeXYWH(x, y,
2005 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
2006 if (NULL == paint || paint->canComputeFastBounds()) {
2007 if (paint) {
2008 paint->computeFastBounds(bounds, &bounds);
2009 }
2010 if (this->quickReject(bounds)) {
2011 return;
2012 }
2013 }
2014
2015 SkLazyPaint lazy;
2016 if (NULL == paint) {
2017 paint = lazy.init();
2018 }
2019
2020 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds)
2021
2022 while (iter.next()) {
2023 iter.fDevice->drawImage(iter, image, x, y, looper.paint());
2024 }
2025
2026 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002027}
2028
reed41af9662015-01-05 07:49:08 -08002029void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2030 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002031 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
reeda85d4d02015-05-06 12:56:48 -07002032 SkRect storage;
2033 const SkRect* bounds = &dst;
2034 if (NULL == paint || paint->canComputeFastBounds()) {
2035 if (paint) {
2036 bounds = &paint->computeFastBounds(dst, &storage);
2037 }
2038 if (this->quickReject(*bounds)) {
2039 return;
2040 }
2041 }
2042 SkLazyPaint lazy;
2043 if (NULL == paint) {
2044 paint = lazy.init();
2045 }
2046
2047 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2048
2049 while (iter.next()) {
2050 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint());
2051 }
2052
2053 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002054}
2055
reed41af9662015-01-05 07:49:08 -08002056void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002057 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002058 SkDEBUGCODE(bitmap.validate();)
2059
reed@google.com3d608122011-11-21 15:16:16 +00002060 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002061 SkRect bounds = {
2062 x, y,
2063 x + SkIntToScalar(bitmap.width()),
2064 y + SkIntToScalar(bitmap.height())
2065 };
2066 if (paint) {
2067 (void)paint->computeFastBounds(bounds, &bounds);
2068 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002069 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002070 return;
2071 }
2072 }
reed@google.com4b226022011-01-11 18:32:13 +00002073
reed@android.com8a1c16f2008-12-17 15:59:43 +00002074 SkMatrix matrix;
2075 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00002076 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002077}
2078
reed@google.com9987ec32011-09-07 11:57:52 +00002079// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002080void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002081 const SkRect& dst, const SkPaint* paint,
2082 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002083 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002084 return;
2085 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002086
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002087 SkRect storage;
2088 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00002089 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002090 if (paint) {
2091 bounds = &paint->computeFastBounds(dst, &storage);
2092 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002093 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002094 return;
2095 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002096 }
reed@google.com3d608122011-11-21 15:16:16 +00002097
reed@google.com33535f32012-09-25 15:37:50 +00002098 SkLazyPaint lazy;
2099 if (NULL == paint) {
2100 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002101 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002102
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002103 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002104
reed@google.com33535f32012-09-25 15:37:50 +00002105 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002106 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00002107 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002108
reed@google.com33535f32012-09-25 15:37:50 +00002109 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002110}
2111
reed41af9662015-01-05 07:49:08 -08002112void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2113 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08002114 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002115 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002116 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00002117}
2118
reed@google.com9987ec32011-09-07 11:57:52 +00002119void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
2120 const SkIRect& center, const SkRect& dst,
2121 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002122 if (bitmap.drawsNothing()) {
2123 return;
2124 }
reed@google.com3d608122011-11-21 15:16:16 +00002125 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00002126 SkRect storage;
2127 const SkRect* bounds = &dst;
2128 if (paint) {
2129 bounds = &paint->computeFastBounds(dst, &storage);
2130 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002131 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002132 return;
2133 }
2134 }
2135
reed@google.com9987ec32011-09-07 11:57:52 +00002136 const int32_t w = bitmap.width();
2137 const int32_t h = bitmap.height();
2138
2139 SkIRect c = center;
2140 // pin center to the bounds of the bitmap
2141 c.fLeft = SkMax32(0, center.fLeft);
2142 c.fTop = SkMax32(0, center.fTop);
2143 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2144 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2145
reed@google.com71121732012-09-18 15:14:33 +00002146 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002147 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00002148 };
2149 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002150 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00002151 };
reed@google.com9987ec32011-09-07 11:57:52 +00002152 SkScalar dstX[4] = {
2153 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2154 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2155 };
2156 SkScalar dstY[4] = {
2157 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2158 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2159 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002160
reed@google.com9987ec32011-09-07 11:57:52 +00002161 if (dstX[1] > dstX[2]) {
2162 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2163 dstX[2] = dstX[1];
2164 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002165
reed@google.com9987ec32011-09-07 11:57:52 +00002166 if (dstY[1] > dstY[2]) {
2167 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2168 dstY[2] = dstY[1];
2169 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002170
reed@google.com9987ec32011-09-07 11:57:52 +00002171 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00002172 SkRect s, d;
2173
reed@google.com9987ec32011-09-07 11:57:52 +00002174 s.fTop = srcY[y];
2175 s.fBottom = srcY[y+1];
2176 d.fTop = dstY[y];
2177 d.fBottom = dstY[y+1];
2178 for (int x = 0; x < 3; x++) {
2179 s.fLeft = srcX[x];
2180 s.fRight = srcX[x+1];
2181 d.fLeft = dstX[x];
2182 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002183 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00002184 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00002185 }
2186 }
2187}
2188
reed41af9662015-01-05 07:49:08 -08002189void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2190 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002191 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002192 SkDEBUGCODE(bitmap.validate();)
2193
2194 // Need a device entry-point, so gpu can use a mesh
2195 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2196}
2197
reed@google.comf67e4cf2011-03-15 20:56:58 +00002198class SkDeviceFilteredPaint {
2199public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002200 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002201 uint32_t filteredFlags = device->filterTextFlags(paint);
2202 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002203 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002204 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002205 fPaint = newPaint;
2206 } else {
2207 fPaint = &paint;
2208 }
2209 }
2210
reed@google.comf67e4cf2011-03-15 20:56:58 +00002211 const SkPaint& paint() const { return *fPaint; }
2212
2213private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002214 const SkPaint* fPaint;
2215 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002216};
2217
bungeman@google.com52c748b2011-08-22 21:30:43 +00002218void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2219 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002220 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002221 draw.fDevice->drawRect(draw, r, paint);
2222 } else {
2223 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002224 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002225 draw.fDevice->drawRect(draw, r, p);
2226 }
2227}
2228
2229void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2230 const char text[], size_t byteLength,
2231 SkScalar x, SkScalar y) {
2232 SkASSERT(byteLength == 0 || text != NULL);
2233
2234 // nothing to draw
2235 if (text == NULL || byteLength == 0 ||
2236 draw.fClip->isEmpty() ||
2237 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2238 return;
2239 }
2240
2241 SkScalar width = 0;
2242 SkPoint start;
2243
2244 start.set(0, 0); // to avoid warning
2245 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2246 SkPaint::kStrikeThruText_Flag)) {
2247 width = paint.measureText(text, byteLength);
2248
2249 SkScalar offsetX = 0;
2250 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2251 offsetX = SkScalarHalf(width);
2252 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2253 offsetX = width;
2254 }
2255 start.set(x - offsetX, y);
2256 }
2257
2258 if (0 == width) {
2259 return;
2260 }
2261
2262 uint32_t flags = paint.getFlags();
2263
2264 if (flags & (SkPaint::kUnderlineText_Flag |
2265 SkPaint::kStrikeThruText_Flag)) {
2266 SkScalar textSize = paint.getTextSize();
2267 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2268 SkRect r;
2269
2270 r.fLeft = start.fX;
2271 r.fRight = start.fX + width;
2272
2273 if (flags & SkPaint::kUnderlineText_Flag) {
2274 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2275 start.fY);
2276 r.fTop = offset;
2277 r.fBottom = offset + height;
2278 DrawRect(draw, paint, r, textSize);
2279 }
2280 if (flags & SkPaint::kStrikeThruText_Flag) {
2281 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2282 start.fY);
2283 r.fTop = offset;
2284 r.fBottom = offset + height;
2285 DrawRect(draw, paint, r, textSize);
2286 }
2287 }
2288}
2289
reed@google.come0d9ce82014-04-23 04:00:17 +00002290void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2291 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002292 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002293
2294 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002295 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002296 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002297 DrawTextDecorations(iter, dfp.paint(),
2298 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002299 }
2300
reed@google.com4e2b3d32011-04-07 14:18:59 +00002301 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302}
2303
reed@google.come0d9ce82014-04-23 04:00:17 +00002304void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2305 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002306 SkPoint textOffset = SkPoint::Make(0, 0);
2307
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002308 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002309
reed@android.com8a1c16f2008-12-17 15:59:43 +00002310 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002311 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002312 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002313 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002314 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002315
reed@google.com4e2b3d32011-04-07 14:18:59 +00002316 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002317}
2318
reed@google.come0d9ce82014-04-23 04:00:17 +00002319void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2320 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002321
2322 SkPoint textOffset = SkPoint::Make(0, constY);
2323
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002324 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002325
reed@android.com8a1c16f2008-12-17 15:59:43 +00002326 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002327 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002328 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002329 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002330 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002331
reed@google.com4e2b3d32011-04-07 14:18:59 +00002332 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002333}
2334
reed@google.come0d9ce82014-04-23 04:00:17 +00002335void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2336 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002337 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002338
reed@android.com8a1c16f2008-12-17 15:59:43 +00002339 while (iter.next()) {
2340 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002341 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002342 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002343
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002344 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002345}
2346
fmalita00d5c2c2014-08-21 08:53:26 -07002347void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2348 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002349
fmalita85d5eb92015-03-04 11:20:12 -08002350 SkRect storage;
2351 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002352 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002353 storage = blob->bounds().makeOffset(x, y);
2354 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002355
fmalita85d5eb92015-03-04 11:20:12 -08002356 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002357 return;
2358 }
2359 }
2360
fmalita024f9962015-03-03 19:08:17 -08002361 // We cannot filter in the looper as we normally do, because the paint is
2362 // incomplete at this point (text-related attributes are embedded within blob run paints).
2363 SkDrawFilter* drawFilter = fMCRec->fFilter;
2364 fMCRec->fFilter = NULL;
2365
fmalita85d5eb92015-03-04 11:20:12 -08002366 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002367
fmalitaaa1b9122014-08-28 14:32:24 -07002368 while (iter.next()) {
2369 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002370 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002371 }
2372
fmalitaaa1b9122014-08-28 14:32:24 -07002373 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002374
2375 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002376}
2377
reed@google.come0d9ce82014-04-23 04:00:17 +00002378// These will become non-virtual, so they always call the (virtual) onDraw... method
2379void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2380 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002381 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002382 this->onDrawText(text, byteLength, x, y, paint);
2383}
2384void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2385 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002386 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002387 this->onDrawPosText(text, byteLength, pos, paint);
2388}
2389void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2390 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002391 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002392 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2393}
2394void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2395 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002396 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002397 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2398}
fmalita00d5c2c2014-08-21 08:53:26 -07002399void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2400 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002401 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002402 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002403 this->onDrawTextBlob(blob, x, y, paint);
2404 }
2405}
reed@google.come0d9ce82014-04-23 04:00:17 +00002406
reed41af9662015-01-05 07:49:08 -08002407void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2408 const SkPoint verts[], const SkPoint texs[],
2409 const SkColor colors[], SkXfermode* xmode,
2410 const uint16_t indices[], int indexCount,
2411 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002412 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002413 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002414
reed@android.com8a1c16f2008-12-17 15:59:43 +00002415 while (iter.next()) {
2416 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002417 colors, xmode, indices, indexCount,
2418 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002419 }
reed@google.com4b226022011-01-11 18:32:13 +00002420
reed@google.com4e2b3d32011-04-07 14:18:59 +00002421 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002422}
2423
dandovb3c9d1c2014-08-12 08:34:29 -07002424void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2425 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002426 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002427 if (NULL == cubics) {
2428 return;
2429 }
mtklein6cfa73a2014-08-13 13:33:49 -07002430
dandovecfff212014-08-04 10:02:00 -07002431 // Since a patch is always within the convex hull of the control points, we discard it when its
2432 // bounding rectangle is completely outside the current clip.
2433 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002434 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002435 if (this->quickReject(bounds)) {
2436 return;
2437 }
mtklein6cfa73a2014-08-13 13:33:49 -07002438
dandovb3c9d1c2014-08-12 08:34:29 -07002439 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2440}
2441
2442void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2443 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2444
dandovecfff212014-08-04 10:02:00 -07002445 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002446
dandovecfff212014-08-04 10:02:00 -07002447 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002448 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002449 }
mtklein6cfa73a2014-08-13 13:33:49 -07002450
dandovecfff212014-08-04 10:02:00 -07002451 LOOPER_END
2452}
2453
reed3cb38402015-02-06 08:36:15 -08002454void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002455 if (dr && !this->quickReject(dr->getBounds())) {
2456 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002457 }
2458}
2459
reed3cb38402015-02-06 08:36:15 -08002460void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002461 dr->draw(this);
2462}
2463
reed71c3c762015-06-24 10:29:17 -07002464void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2465 const SkColor colors[], int count, SkXfermode::Mode mode,
2466 const SkRect* cull, const SkPaint* paint) {
2467 if (cull && this->quickReject(*cull)) {
2468 return;
2469 }
2470
2471 SkPaint pnt;
2472 if (paint) {
2473 pnt = *paint;
2474 }
2475
2476 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, NULL)
2477 while (iter.next()) {
2478 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2479 }
2480 LOOPER_END
2481}
2482
reed@android.com8a1c16f2008-12-17 15:59:43 +00002483//////////////////////////////////////////////////////////////////////////////
2484// These methods are NOT virtual, and therefore must call back into virtual
2485// methods, rather than actually drawing themselves.
2486//////////////////////////////////////////////////////////////////////////////
2487
2488void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002489 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002490 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002491 SkPaint paint;
2492
2493 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002494 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002495 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496 }
2497 this->drawPaint(paint);
2498}
2499
reed@android.com845fdac2009-06-23 03:01:32 +00002500void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002501 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002502 SkPaint paint;
2503
2504 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002505 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002506 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002507 }
2508 this->drawPaint(paint);
2509}
2510
2511void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002512 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002513 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002514
reed@android.com8a1c16f2008-12-17 15:59:43 +00002515 pt.set(x, y);
2516 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2517}
2518
2519void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002520 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002521 SkPoint pt;
2522 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002523
reed@android.com8a1c16f2008-12-17 15:59:43 +00002524 pt.set(x, y);
2525 paint.setColor(color);
2526 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2527}
2528
2529void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2530 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002531 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002532 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002533
reed@android.com8a1c16f2008-12-17 15:59:43 +00002534 pts[0].set(x0, y0);
2535 pts[1].set(x1, y1);
2536 this->drawPoints(kLines_PointMode, 2, pts, paint);
2537}
2538
2539void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2540 SkScalar right, SkScalar bottom,
2541 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002542 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002543 SkRect r;
2544
2545 r.set(left, top, right, bottom);
2546 this->drawRect(r, paint);
2547}
2548
2549void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2550 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002551 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002552 if (radius < 0) {
2553 radius = 0;
2554 }
2555
2556 SkRect r;
2557 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002558 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002559}
2560
2561void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2562 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002563 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002564 if (rx > 0 && ry > 0) {
2565 if (paint.canComputeFastBounds()) {
2566 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002567 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002568 return;
2569 }
2570 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002571 SkRRect rrect;
2572 rrect.setRectXY(r, rx, ry);
2573 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002574 } else {
2575 this->drawRect(r, paint);
2576 }
2577}
2578
reed@android.com8a1c16f2008-12-17 15:59:43 +00002579void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2580 SkScalar sweepAngle, bool useCenter,
2581 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002582 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002583 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2584 this->drawOval(oval, paint);
2585 } else {
2586 SkPath path;
2587 if (useCenter) {
2588 path.moveTo(oval.centerX(), oval.centerY());
2589 }
2590 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2591 if (useCenter) {
2592 path.close();
2593 }
2594 this->drawPath(path, paint);
2595 }
2596}
2597
2598void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2599 const SkPath& path, SkScalar hOffset,
2600 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002601 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002602 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002603
reed@android.com8a1c16f2008-12-17 15:59:43 +00002604 matrix.setTranslate(hOffset, vOffset);
2605 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2606}
2607
reed@android.comf76bacf2009-05-13 14:00:33 +00002608///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002609
2610/**
2611 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2612 * against the playback cost of recursing into the subpicture to get at its actual ops.
2613 *
2614 * For now we pick a conservatively small value, though measurement (and other heuristics like
2615 * the type of ops contained) may justify changing this value.
2616 */
2617#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002618
reedd5fa1a42014-08-09 11:08:05 -07002619void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002620 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002621 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002622 if (matrix && matrix->isIdentity()) {
2623 matrix = NULL;
2624 }
reed1c2c4412015-04-30 13:09:24 -07002625 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2626 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2627 picture->playback(this);
2628 } else {
2629 this->onDrawPicture(picture, matrix, paint);
2630 }
reedd5fa1a42014-08-09 11:08:05 -07002631 }
2632}
robertphillips9b14f262014-06-04 05:40:44 -07002633
reedd5fa1a42014-08-09 11:08:05 -07002634void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2635 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002636 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002637 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002638 // Canvas has to first give the device the opportunity to render
2639 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002640 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002641 return; // the device has rendered the entire picture
2642 }
2643 }
2644
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002645 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002646 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002647}
2648
reed@android.com8a1c16f2008-12-17 15:59:43 +00002649///////////////////////////////////////////////////////////////////////////////
2650///////////////////////////////////////////////////////////////////////////////
2651
2652SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002653 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002654
2655 SkASSERT(canvas);
2656
2657 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2658 fDone = !fImpl->next();
2659}
2660
2661SkCanvas::LayerIter::~LayerIter() {
2662 fImpl->~SkDrawIter();
2663}
2664
2665void SkCanvas::LayerIter::next() {
2666 fDone = !fImpl->next();
2667}
2668
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002669SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002670 return fImpl->getDevice();
2671}
2672
2673const SkMatrix& SkCanvas::LayerIter::matrix() const {
2674 return fImpl->getMatrix();
2675}
2676
2677const SkPaint& SkCanvas::LayerIter::paint() const {
2678 const SkPaint* paint = fImpl->getPaint();
2679 if (NULL == paint) {
2680 paint = &fDefaultPaint;
2681 }
2682 return *paint;
2683}
2684
2685const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2686int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2687int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002688
2689///////////////////////////////////////////////////////////////////////////////
2690
fmalitac3b589a2014-06-05 12:40:07 -07002691SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002692
2693///////////////////////////////////////////////////////////////////////////////
2694
2695static bool supported_for_raster_canvas(const SkImageInfo& info) {
2696 switch (info.alphaType()) {
2697 case kPremul_SkAlphaType:
2698 case kOpaque_SkAlphaType:
2699 break;
2700 default:
2701 return false;
2702 }
2703
2704 switch (info.colorType()) {
2705 case kAlpha_8_SkColorType:
2706 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002707 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002708 break;
2709 default:
2710 return false;
2711 }
2712
2713 return true;
2714}
2715
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002716SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2717 if (!supported_for_raster_canvas(info)) {
2718 return NULL;
2719 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002720
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002721 SkBitmap bitmap;
2722 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2723 return NULL;
2724 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002725 return SkNEW_ARGS(SkCanvas, (bitmap));
2726}
reedd5fa1a42014-08-09 11:08:05 -07002727
2728///////////////////////////////////////////////////////////////////////////////
2729
2730SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002731 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002732 : fCanvas(canvas)
2733 , fSaveCount(canvas->getSaveCount())
2734{
bsalomon49f085d2014-09-05 13:34:00 -07002735 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002736 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002737 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002738 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002739 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002740 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002741 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002742 canvas->save();
2743 }
mtklein6cfa73a2014-08-13 13:33:49 -07002744
bsalomon49f085d2014-09-05 13:34:00 -07002745 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002746 canvas->concat(*matrix);
2747 }
2748}
2749
2750SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2751 fCanvas->restoreToCount(fSaveCount);
2752}