blob: 88339ff4f387c8989a145dc37bb6d48d7b84734d [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"
reed4c21dc52015-06-25 12:32:03 -070019#include "SkNinePatchIter.h"
caryclark@google.com45a75fb2013-04-25 13:34:40 +000020#include "SkPathOps.h"
dandovb3c9d1c2014-08-12 08:34:29 -070021#include "SkPatchUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000022#include "SkPicture.h"
reed@google.com00177082011-10-12 14:34:30 +000023#include "SkRasterClip.h"
reed96472de2014-12-10 09:53:42 -080024#include "SkReadPixelsRec.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000025#include "SkRRect.h"
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +000026#include "SkSmallAllocator.h"
reed@google.com97af1a62012-08-28 12:19:02 +000027#include "SkSurface_Base.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000028#include "SkTemplates.h"
fmalita7ba7aa72014-08-29 09:46:36 -070029#include "SkTextBlob.h"
bungeman@google.com52c748b2011-08-22 21:30:43 +000030#include "SkTextFormatParams.h"
reed@google.coma076e9b2011-04-06 20:17:29 +000031#include "SkTLazy.h"
danakj8f757f52014-11-04 11:48:43 -080032#include "SkTraceEvent.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000033#include "SkUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000034
commit-bot@chromium.org644629c2013-11-21 06:21:58 +000035#if SK_SUPPORT_GPU
36#include "GrRenderTarget.h"
37#endif
38
reedd990e2f2014-12-22 11:58:30 -080039static bool gIgnoreSaveLayerBounds;
40void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
41 gIgnoreSaveLayerBounds = ignore;
42}
43bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
44 return gIgnoreSaveLayerBounds;
45}
46
reed0acf1b42014-12-22 16:12:38 -080047static bool gTreatSpriteAsBitmap;
48void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
49 gTreatSpriteAsBitmap = spriteAsBitmap;
50}
51bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
52 return gTreatSpriteAsBitmap;
53}
54
reed@google.comda17f752012-08-16 18:27:05 +000055// experimental for faster tiled drawing...
56//#define SK_ENABLE_CLIP_QUICKREJECT
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000057
reed@android.com8a1c16f2008-12-17 15:59:43 +000058//#define SK_TRACE_SAVERESTORE
59
60#ifdef SK_TRACE_SAVERESTORE
61 static int gLayerCounter;
62 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
63 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
64
65 static int gRecCounter;
66 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
67 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
68
69 static int gCanvasCounter;
70 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
71 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
72#else
73 #define inc_layer()
74 #define dec_layer()
75 #define inc_rec()
76 #define dec_rec()
77 #define inc_canvas()
78 #define dec_canvas()
79#endif
80
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +000081typedef SkTLazy<SkPaint> SkLazyPaint;
82
reed@google.com97af1a62012-08-28 12:19:02 +000083void SkCanvas::predrawNotify() {
84 if (fSurfaceBase) {
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +000085 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode);
reed@google.com97af1a62012-08-28 12:19:02 +000086 }
87}
88
reed@android.com8a1c16f2008-12-17 15:59:43 +000089///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000090
reed4a8126e2014-09-22 07:29:03 -070091static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
92 const uint32_t propFlags = props.flags();
93 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
94 flags &= ~SkPaint::kDither_Flag;
95 }
96 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
97 flags &= ~SkPaint::kAntiAlias_Flag;
98 }
99 return flags;
100}
101
102///////////////////////////////////////////////////////////////////////////////
103
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000104/* This is the record we keep for each SkBaseDevice that the user installs.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105 The clip/matrix/proc are fields that reflect the top of the save/restore
106 stack. Whenever the canvas changes, it marks a dirty flag, and then before
107 these are used (assuming we're not on a layer) we rebuild these cache
108 values: they reflect the top of the save stack, but translated and clipped
109 by the device's XY offset and bitmap-bounds.
110*/
111struct DeviceCM {
112 DeviceCM* fNext;
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000113 SkBaseDevice* fDevice;
reed@google.com045e62d2011-10-24 12:19:46 +0000114 SkRasterClip fClip;
reed@google.com6f8f2922011-03-04 22:27:10 +0000115 SkPaint* fPaint; // may be null (in the future)
reed61f501f2015-04-29 08:34:00 -0700116 const SkMatrix* fMatrix;
117 SkMatrix fMatrixStorage;
118 const bool fDeviceIsBitmapDevice;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119
reed96e657d2015-03-10 17:30:07 -0700120 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
reed86a17e72015-05-14 12:25:22 -0700121 bool conservativeRasterClip, bool deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700122 : fNext(NULL)
123 , fClip(conservativeRasterClip)
reed61f501f2015-04-29 08:34:00 -0700124 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700125 {
126 if (NULL != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000128 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 }
reed@google.com4b226022011-01-11 18:32:13 +0000130 fDevice = device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000132 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000134 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700135 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000136 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137 fDevice->unref();
138 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000139 SkDELETE(fPaint);
140 }
reed@google.com4b226022011-01-11 18:32:13 +0000141
mtkleinfeaadee2015-04-08 11:25:48 -0700142 void reset(const SkIRect& bounds) {
143 SkASSERT(!fPaint);
144 SkASSERT(!fNext);
145 SkASSERT(fDevice);
146 fClip.setRect(bounds);
147 }
148
reed@google.com045e62d2011-10-24 12:19:46 +0000149 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
150 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000151 int x = fDevice->getOrigin().x();
152 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 int width = fDevice->width();
154 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000155
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156 if ((x | y) == 0) {
157 fMatrix = &totalMatrix;
158 fClip = totalClip;
159 } else {
160 fMatrixStorage = totalMatrix;
161 fMatrixStorage.postTranslate(SkIntToScalar(-x),
162 SkIntToScalar(-y));
163 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000164
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 totalClip.translate(-x, -y, &fClip);
166 }
167
reed@google.com045e62d2011-10-24 12:19:46 +0000168 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169
170 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000171
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000173 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174 SkRegion::kDifference_Op);
175 }
reed@google.com4b226022011-01-11 18:32:13 +0000176
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000177 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
178
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179#ifdef SK_DEBUG
180 if (!fClip.isEmpty()) {
181 SkIRect deviceR;
182 deviceR.set(0, 0, width, height);
183 SkASSERT(deviceR.contains(fClip.getBounds()));
184 }
185#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000186 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187};
188
189/* This is the record we keep for each save/restore level in the stack.
190 Since a level optionally copies the matrix and/or stack, we have pointers
191 for these fields. If the value is copied for this level, the copy is
192 stored in the ...Storage field, and the pointer points to that. If the
193 value is not copied for this level, we ignore ...Storage, and just point
194 at the corresponding value in the previous level in the stack.
195*/
196class SkCanvas::MCRec {
197public:
reed1f836ee2014-07-07 07:49:34 -0700198 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700199 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 /* If there are any layers in the stack, this points to the top-most
201 one that is at or below this level in the stack (so we know what
202 bitmap/device to draw into from this level. This value is NOT
203 reference counted, since the real owner is either our fLayer field,
204 or a previous one in a lower level.)
205 */
reed2ff1fce2014-12-11 07:07:37 -0800206 DeviceCM* fTopLayer;
207 SkRasterClip fRasterClip;
208 SkMatrix fMatrix;
209 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210
reedd9544982014-09-09 18:46:22 -0700211 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
reedd9544982014-09-09 18:46:22 -0700212 fFilter = NULL;
213 fLayer = NULL;
214 fTopLayer = NULL;
reed2ff1fce2014-12-11 07:07:37 -0800215 fMatrix.reset();
216 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700217
reedd9544982014-09-09 18:46:22 -0700218 // don't bother initializing fNext
219 inc_rec();
220 }
reed2ff1fce2014-12-11 07:07:37 -0800221 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700222 fFilter = SkSafeRef(prev.fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 fLayer = NULL;
reedd9544982014-09-09 18:46:22 -0700224 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800225 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700226
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 // don't bother initializing fNext
228 inc_rec();
229 }
230 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000231 SkSafeUnref(fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 SkDELETE(fLayer);
233 dec_rec();
234 }
mtkleinfeaadee2015-04-08 11:25:48 -0700235
236 void reset(const SkIRect& bounds) {
237 SkASSERT(fLayer);
238 SkASSERT(fDeferredSaveCount == 0);
239
240 fMatrix.reset();
241 fRasterClip.setRect(bounds);
242 fLayer->reset(bounds);
243 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244};
245
246class SkDrawIter : public SkDraw {
247public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000248 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000249 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000250 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 canvas->updateDeviceCMCache();
252
reed687fa1c2015-04-07 08:00:56 -0700253 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000255 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256 }
reed@google.com4b226022011-01-11 18:32:13 +0000257
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258 bool next() {
259 // skip over recs with empty clips
260 if (fSkipEmptyClips) {
261 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
262 fCurrLayer = fCurrLayer->fNext;
263 }
264 }
265
reed@google.comf68c5e22012-02-24 16:38:58 +0000266 const DeviceCM* rec = fCurrLayer;
267 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268
269 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000270 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
271 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 fDevice = rec->fDevice;
reed41e010c2015-06-09 12:16:53 -0700273 if (!fDevice->accessPixels(&fDst)) {
274 fDst.reset(fDevice->imageInfo(), NULL, 0);
275 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000277 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278
279 fCurrLayer = rec->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 // fCurrLayer may be NULL now
reed@android.com199f1082009-06-10 02:12:47 +0000281
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282 return true;
283 }
284 return false;
285 }
reed@google.com4b226022011-01-11 18:32:13 +0000286
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000287 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000288 int getX() const { return fDevice->getOrigin().x(); }
289 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 const SkMatrix& getMatrix() const { return *fMatrix; }
291 const SkRegion& getClip() const { return *fClip; }
292 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000293
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294private:
295 SkCanvas* fCanvas;
296 const DeviceCM* fCurrLayer;
297 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298 SkBool8 fSkipEmptyClips;
299
300 typedef SkDraw INHERITED;
301};
302
303/////////////////////////////////////////////////////////////////////////////
304
reeddbc3cef2015-04-29 12:18:57 -0700305static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
306 return lazy->isValid() ? lazy->get() : lazy->set(orig);
307}
308
309/**
310 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
311 * colorfilter, else return NULL.
312 */
313static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700314 SkImageFilter* imgf = paint.getImageFilter();
315 if (!imgf) {
316 return NULL;
317 }
318
319 SkColorFilter* imgCF;
320 if (!imgf->asAColorFilter(&imgCF)) {
321 return NULL;
322 }
323
324 SkColorFilter* paintCF = paint.getColorFilter();
325 if (NULL == paintCF) {
326 // there is no existing paint colorfilter, so we can just return the imagefilter's
327 return imgCF;
328 }
329
330 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
331 // and we need to combine them into a single colorfilter.
332 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
333 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
reeddbc3cef2015-04-29 12:18:57 -0700334}
335
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336class AutoDrawLooper {
337public:
reed4a8126e2014-09-22 07:29:03 -0700338 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000339 bool skipLayerForImageFilter = false,
340 const SkRect* bounds = NULL) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000341 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700343 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000344 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700345 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000346 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347
reeddbc3cef2015-04-29 12:18:57 -0700348 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
349 if (simplifiedCF) {
350 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
351 paint->setColorFilter(simplifiedCF)->unref();
352 paint->setImageFilter(NULL);
353 fPaint = paint;
354 }
355
356 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700357 /**
358 * We implement ImageFilters for a given draw by creating a layer, then applying the
359 * imagefilter to the pixels of that layer (its backing surface/image), and then
360 * we call restore() to xfer that layer to the main canvas.
361 *
362 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
363 * 2. Generate the src pixels:
364 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
365 * return (fPaint). We then draw the primitive (using srcover) into a cleared
366 * buffer/surface.
367 * 3. Restore the layer created in #1
368 * The imagefilter is passed the buffer/surface from the layer (now filled with the
369 * src pixels of the primitive). It returns a new "filtered" buffer, which we
370 * draw onto the previous layer using the xfermode from the original paint.
371 */
reed@google.com8926b162012-03-23 15:36:36 +0000372 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700373 tmp.setImageFilter(fPaint->getImageFilter());
374 tmp.setXfermode(fPaint->getXfermode());
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000375 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
reed76033be2015-03-14 10:54:31 -0700376 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700377 fTempLayerForImageFilter = true;
378 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000379 }
380
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000381 if (SkDrawLooper* looper = paint.getLooper()) {
382 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
383 looper->contextSize());
384 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000385 fIsSimple = false;
386 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000387 fLooperContext = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000388 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700389 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000390 }
piotaixrb5fae932014-09-24 13:03:30 -0700391
reed4a8126e2014-09-22 07:29:03 -0700392 uint32_t oldFlags = paint.getFlags();
393 fNewPaintFlags = filter_paint_flags(props, oldFlags);
394 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700395 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700396 paint->setFlags(fNewPaintFlags);
397 fPaint = paint;
398 // if we're not simple, doNext() will take care of calling setFlags()
399 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000400 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000401
reed@android.com8a1c16f2008-12-17 15:59:43 +0000402 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700403 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000404 fCanvas->internalRestore();
405 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000406 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000407 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000408
reed@google.com4e2b3d32011-04-07 14:18:59 +0000409 const SkPaint& paint() const {
410 SkASSERT(fPaint);
411 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000412 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000413
reed@google.com129ec222012-05-15 13:24:09 +0000414 bool next(SkDrawFilter::Type drawType) {
415 if (fDone) {
416 return false;
417 } else if (fIsSimple) {
418 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000419 return !fPaint->nothingToDraw();
420 } else {
421 return this->doNext(drawType);
422 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000423 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000424
reed@android.com8a1c16f2008-12-17 15:59:43 +0000425private:
reeddbc3cef2015-04-29 12:18:57 -0700426 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
427 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000428 SkCanvas* fCanvas;
429 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000430 SkDrawFilter* fFilter;
431 const SkPaint* fPaint;
432 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700433 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700434 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000435 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000436 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000437 SkDrawLooper::Context* fLooperContext;
438 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000439
440 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441};
442
reed@google.com129ec222012-05-15 13:24:09 +0000443bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
reed@google.com632e1a22011-10-06 12:37:00 +0000444 fPaint = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000445 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700446 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000447
reeddbc3cef2015-04-29 12:18:57 -0700448 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
449 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700450 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000451
reed5c476fb2015-04-20 08:04:21 -0700452 if (fTempLayerForImageFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000453 paint->setImageFilter(NULL);
reed5c476fb2015-04-20 08:04:21 -0700454 paint->setXfermode(NULL);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000455 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000456
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000457 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000458 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000459 return false;
460 }
461 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000462 if (!fFilter->filter(paint, drawType)) {
463 fDone = true;
464 return false;
465 }
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000466 if (NULL == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000467 // no looper means we only draw once
468 fDone = true;
469 }
470 }
471 fPaint = paint;
472
473 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000474 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000475 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000476 }
477
478 // call this after any possible paint modifiers
479 if (fPaint->nothingToDraw()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000480 fPaint = NULL;
481 return false;
482 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000483 return true;
484}
485
reed@android.com8a1c16f2008-12-17 15:59:43 +0000486////////// macros to place around the internal draw calls //////////////////
487
reed@google.com8926b162012-03-23 15:36:36 +0000488#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000489 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700490 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000491 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000492 SkDrawIter iter(this);
493
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000494#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000495 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700496 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000497 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000499
reed@google.com4e2b3d32011-04-07 14:18:59 +0000500#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000501
502////////////////////////////////////////////////////////////////////////////
503
mtkleinfeaadee2015-04-08 11:25:48 -0700504void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
505 this->restoreToCount(1);
506 fCachedLocalClipBounds.setEmpty();
507 fCachedLocalClipBoundsDirty = true;
508 fClipStack->reset();
509 fMCRec->reset(bounds);
510
511 // We're peering through a lot of structs here. Only at this scope do we
512 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
513 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
514}
515
reedd9544982014-09-09 18:46:22 -0700516SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
517 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
reed@google.comc0784db2013-12-13 21:16:12 +0000518 fCachedLocalClipBounds.setEmpty();
519 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000520 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000521 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700522 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800523 fSaveCount = 1;
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000524 fMetaData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525
reed687fa1c2015-04-07 08:00:56 -0700526 fClipStack.reset(SkNEW(SkClipStack));
527
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700529 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530
reeda499f902015-05-01 09:34:31 -0700531 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
532 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
reed86a17e72015-05-14 12:25:22 -0700533 new (fDeviceCMStorage) DeviceCM(NULL, NULL, NULL, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700534
reed@android.com8a1c16f2008-12-17 15:59:43 +0000535 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000536
reed@google.com97af1a62012-08-28 12:19:02 +0000537 fSurfaceBase = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000538
reedf92c8662014-08-18 08:02:43 -0700539 if (device) {
robertphillipsefbffed2015-06-22 12:06:08 -0700540 // The root device and the canvas should always have the same pixel geometry
541 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700542 if (device->forceConservativeRasterClip()) {
543 fConservativeRasterClip = true;
544 }
reedf92c8662014-08-18 08:02:43 -0700545 device->onAttachToCanvas(this);
546 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800547 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700548 }
549 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000550}
551
reed@google.comcde92112011-07-06 20:00:52 +0000552SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000553 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700554 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000555{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000556 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000557
reedd9544982014-09-09 18:46:22 -0700558 this->init(NULL, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000559}
560
reedd9544982014-09-09 18:46:22 -0700561static SkBitmap make_nopixels(int width, int height) {
562 SkBitmap bitmap;
563 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
564 return bitmap;
565}
566
567class SkNoPixelsBitmapDevice : public SkBitmapDevice {
568public:
robertphillipsfcf78292015-06-19 11:49:52 -0700569 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
570 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
reed78e27682014-11-19 08:04:34 -0800571 {
572 this->setOrigin(bounds.x(), bounds.y());
573 }
reedd9544982014-09-09 18:46:22 -0700574
575private:
piotaixrb5fae932014-09-24 13:03:30 -0700576
reedd9544982014-09-09 18:46:22 -0700577 typedef SkBitmapDevice INHERITED;
578};
579
reed96a857e2015-01-25 10:33:58 -0800580SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000581 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800582 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000583{
584 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700585
reed78e27682014-11-19 08:04:34 -0800586 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
robertphillipsfcf78292015-06-19 11:49:52 -0700587 (SkIRect::MakeWH(width, height), fProps)), kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700588}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000589
reed78e27682014-11-19 08:04:34 -0800590SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700591 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700592 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700593{
594 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700595
robertphillipsfcf78292015-06-19 11:49:52 -0700596 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds, fProps)), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700597}
598
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000599SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000600 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700601 , fProps(device->surfaceProps())
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000602{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700604
reedd9544982014-09-09 18:46:22 -0700605 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000606}
607
robertphillipsfcf78292015-06-19 11:49:52 -0700608SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
609 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
robertphillips7b05ff12015-06-19 14:14:54 -0700610 , fProps(device->surfaceProps())
robertphillipsfcf78292015-06-19 11:49:52 -0700611{
612 inc_canvas();
613
614 this->init(device, flags);
615}
616
reed4a8126e2014-09-22 07:29:03 -0700617SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700618 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700619 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700620{
621 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700622
robertphillipsfcf78292015-06-19 11:49:52 -0700623 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap, fProps)));
reed4a8126e2014-09-22 07:29:03 -0700624 this->init(device, kDefault_InitFlags);
625}
reed29c857d2014-09-21 10:25:07 -0700626
reed4a8126e2014-09-22 07:29:03 -0700627SkCanvas::SkCanvas(const SkBitmap& bitmap)
628 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
629 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
630{
631 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700632
robertphillipsfcf78292015-06-19 11:49:52 -0700633 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap, fProps)));
reed4a8126e2014-09-22 07:29:03 -0700634 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000635}
636
637SkCanvas::~SkCanvas() {
638 // free up the contents of our deque
639 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000640
reed@android.com8a1c16f2008-12-17 15:59:43 +0000641 this->internalRestore(); // restore the last, since we're going away
642
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000643 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000644
reed@android.com8a1c16f2008-12-17 15:59:43 +0000645 dec_canvas();
646}
647
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648SkDrawFilter* SkCanvas::getDrawFilter() const {
649 return fMCRec->fFilter;
650}
651
652SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700653 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000654 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
655 return filter;
656}
657
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000658SkMetaData& SkCanvas::getMetaData() {
659 // metadata users are rare, so we lazily allocate it. If that changes we
660 // can decide to just make it a field in the device (rather than a ptr)
661 if (NULL == fMetaData) {
662 fMetaData = new SkMetaData;
663 }
664 return *fMetaData;
665}
666
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667///////////////////////////////////////////////////////////////////////////////
668
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000669void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000670 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000671 if (device) {
672 device->flush();
673 }
674}
675
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000676SkISize SkCanvas::getTopLayerSize() const {
677 SkBaseDevice* d = this->getTopDevice();
678 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
679}
680
681SkIPoint SkCanvas::getTopLayerOrigin() const {
682 SkBaseDevice* d = this->getTopDevice();
683 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
684}
685
686SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000687 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000688 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
689}
690
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000691SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000693 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000694 SkASSERT(rec && rec->fLayer);
695 return rec->fLayer->fDevice;
696}
697
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000698SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000699 if (updateMatrixClip) {
700 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
701 }
reed@google.com9266fed2011-03-30 00:18:03 +0000702 return fMCRec->fTopLayer->fDevice;
703}
704
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000705bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
706 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
707 return false;
708 }
709
710 bool weAllocated = false;
711 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700712 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000713 return false;
714 }
715 weAllocated = true;
716 }
717
reedcf01e312015-05-23 19:14:51 -0700718 SkAutoPixmapUnlock unlocker;
719 if (bitmap->requestLock(&unlocker)) {
720 const SkPixmap& pm = unlocker.pixmap();
721 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
722 return true;
723 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000724 }
725
726 if (weAllocated) {
727 bitmap->setPixelRef(NULL);
728 }
729 return false;
730}
reed@google.com51df9e32010-12-23 19:29:18 +0000731
bsalomon@google.comc6980972011-11-02 19:57:21 +0000732bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000733 SkIRect r = srcRect;
734 const SkISize size = this->getBaseLayerSize();
735 if (!r.intersect(0, 0, size.width(), size.height())) {
736 bitmap->reset();
737 return false;
738 }
739
reed84825042014-09-02 12:50:45 -0700740 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000741 // bitmap will already be reset.
742 return false;
743 }
744 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
745 bitmap->reset();
746 return false;
747 }
748 return true;
749}
750
reed96472de2014-12-10 09:53:42 -0800751bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000752 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000753 if (!device) {
754 return false;
755 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000756 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800757
reed96472de2014-12-10 09:53:42 -0800758 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
759 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000760 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000761 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000762
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000763 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800764 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000765}
766
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000767bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
768 if (bitmap.getTexture()) {
769 return false;
770 }
reedcf01e312015-05-23 19:14:51 -0700771
772 SkAutoPixmapUnlock unlocker;
773 if (bitmap.requestLock(&unlocker)) {
774 const SkPixmap& pm = unlocker.pixmap();
775 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000776 }
777 return false;
778}
779
780bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
781 int x, int y) {
782 switch (origInfo.colorType()) {
783 case kUnknown_SkColorType:
784 case kIndex_8_SkColorType:
785 return false;
786 default:
787 break;
788 }
789 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
790 return false;
791 }
792
793 const SkISize size = this->getBaseLayerSize();
794 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
795 if (!target.intersect(0, 0, size.width(), size.height())) {
796 return false;
797 }
798
799 SkBaseDevice* device = this->getDevice();
800 if (!device) {
801 return false;
802 }
803
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000804 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700805 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000806
807 // if x or y are negative, then we have to adjust pixels
808 if (x > 0) {
809 x = 0;
810 }
811 if (y > 0) {
812 y = 0;
813 }
814 // here x,y are either 0 or negative
815 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
816
reed4af35f32014-06-27 17:47:49 -0700817 // Tell our owning surface to bump its generation ID
818 this->predrawNotify();
819
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000820 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000821 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000822}
reed@google.com51df9e32010-12-23 19:29:18 +0000823
junov@google.com4370aed2012-01-18 16:21:08 +0000824SkCanvas* SkCanvas::canvasForDrawIter() {
825 return this;
826}
827
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828//////////////////////////////////////////////////////////////////////////////
829
reed@android.com8a1c16f2008-12-17 15:59:43 +0000830void SkCanvas::updateDeviceCMCache() {
831 if (fDeviceCMDirty) {
832 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700833 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000834 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000835
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836 if (NULL == layer->fNext) { // only one layer
reed687fa1c2015-04-07 08:00:56 -0700837 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000838 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000839 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000840 do {
reed687fa1c2015-04-07 08:00:56 -0700841 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000842 } while ((layer = layer->fNext) != NULL);
843 }
844 fDeviceCMDirty = false;
845 }
846}
847
reed@android.com8a1c16f2008-12-17 15:59:43 +0000848///////////////////////////////////////////////////////////////////////////////
849
reed2ff1fce2014-12-11 07:07:37 -0800850void SkCanvas::checkForDeferredSave() {
851 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800852 this->doSave();
853 }
854}
855
reedf0090cb2014-11-26 08:55:51 -0800856int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800857#ifdef SK_DEBUG
858 int count = 0;
859 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
860 for (;;) {
861 const MCRec* rec = (const MCRec*)iter.next();
862 if (!rec) {
863 break;
864 }
865 count += 1 + rec->fDeferredSaveCount;
866 }
867 SkASSERT(count == fSaveCount);
868#endif
869 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800870}
871
872int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800873 fSaveCount += 1;
874 fMCRec->fDeferredSaveCount += 1;
875 return this->getSaveCount() - 1; // return our prev value
876}
877
878void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800879 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700880
881 SkASSERT(fMCRec->fDeferredSaveCount > 0);
882 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800883 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800884}
885
886void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800887 if (fMCRec->fDeferredSaveCount > 0) {
888 SkASSERT(fSaveCount > 1);
889 fSaveCount -= 1;
890 fMCRec->fDeferredSaveCount -= 1;
891 } else {
892 // check for underflow
893 if (fMCStack.count() > 1) {
894 this->willRestore();
895 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700896 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800897 this->internalRestore();
898 this->didRestore();
899 }
reedf0090cb2014-11-26 08:55:51 -0800900 }
901}
902
903void SkCanvas::restoreToCount(int count) {
904 // sanity check
905 if (count < 1) {
906 count = 1;
907 }
mtkleinf0f14112014-12-12 08:46:25 -0800908
reedf0090cb2014-11-26 08:55:51 -0800909 int n = this->getSaveCount() - count;
910 for (int i = 0; i < n; ++i) {
911 this->restore();
912 }
913}
914
reed2ff1fce2014-12-11 07:07:37 -0800915void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000916 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700917 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000918 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000919
reed687fa1c2015-04-07 08:00:56 -0700920 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000921}
922
reed@android.com8a1c16f2008-12-17 15:59:43 +0000923static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000924#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000925 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000926#else
927 return true;
928#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000929}
930
junov@chromium.orga907ac32012-02-24 21:54:07 +0000931bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700932 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000933 SkIRect clipBounds;
934 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000935 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000936 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000937
reed96e657d2015-03-10 17:30:07 -0700938 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
939
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000940 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700941 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000942 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000943 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700944 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000945 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000946
reed96e657d2015-03-10 17:30:07 -0700947 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000948 r.roundOut(&ir);
949 // early exit if the layer's bounds are clipped out
950 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000951 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700952 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700953 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000954 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000955 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000956 }
957 } else { // no user bounds, so just use the clip
958 ir = clipBounds;
959 }
reed180aec42015-03-11 10:39:04 -0700960 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000961
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000962 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -0700963 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -0700964 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -0700965 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -0700966 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000967 }
968
969 if (intersection) {
970 *intersection = ir;
971 }
972 return true;
973}
974
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000975int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800976 if (gIgnoreSaveLayerBounds) {
977 bounds = NULL;
978 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000979 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -0700980 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700981 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800982 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000983}
984
reed2ff1fce2014-12-11 07:07:37 -0800985int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800986 if (gIgnoreSaveLayerBounds) {
987 bounds = NULL;
988 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000989 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -0700990 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700991 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800992 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000993}
994
reed2ff1fce2014-12-11 07:07:37 -0800995void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -0700996 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000997#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000998 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000999#endif
1000
junov@chromium.orga907ac32012-02-24 21:54:07 +00001001 // do this before we create the layer. We don't call the public save() since
1002 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001003 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001004
1005 fDeviceCMDirty = true;
1006
1007 SkIRect ir;
reeddaa57bf2015-05-15 10:39:17 -07001008 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -08001009 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001010 }
1011
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001012 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1013 // the clipRectBounds() call above?
1014 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001015 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001016 }
1017
reed76033be2015-03-14 10:54:31 -07001018 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001019 SkPixelGeometry geo = fProps.pixelGeometry();
1020 if (paint) {
reed76033be2015-03-14 10:54:31 -07001021 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001022 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001023 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001024 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001025 }
1026 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001027 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1028 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001029
reedb2db8982014-11-13 12:41:02 -08001030 SkBaseDevice* device = this->getTopDevice();
1031 if (NULL == device) {
1032 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001033 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001034 }
reedb2db8982014-11-13 12:41:02 -08001035
reed61f501f2015-04-29 08:34:00 -07001036 bool forceSpriteOnRestore = false;
1037 {
reeddaa57bf2015-05-15 10:39:17 -07001038 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed61f501f2015-04-29 08:34:00 -07001039 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo);
1040 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
1041 if (NULL == newDev) {
1042 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
robertphillips9a53fd72015-06-22 09:46:59 -07001043 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1044 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
reed61f501f2015-04-29 08:34:00 -07001045 if (NULL == newDev) {
1046 SkErrorInternals::SetError(kInternalError_SkError,
1047 "Unable to create device for layer.");
1048 return;
1049 }
1050 forceSpriteOnRestore = true;
1051 }
1052 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001053 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001054
reed@google.com6f8f2922011-03-04 22:27:10 +00001055 device->setOrigin(ir.fLeft, ir.fTop);
reed61f501f2015-04-29 08:34:00 -07001056 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip,
reed86a17e72015-05-14 12:25:22 -07001057 forceSpriteOnRestore));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001058 device->unref();
1059
1060 layer->fNext = fMCRec->fTopLayer;
1061 fMCRec->fLayer = layer;
1062 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001063}
1064
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001065int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1066 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1067}
1068
reed@android.com8a1c16f2008-12-17 15:59:43 +00001069int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1070 SaveFlags flags) {
1071 if (0xFF == alpha) {
1072 return this->saveLayer(bounds, NULL, flags);
1073 } else {
1074 SkPaint tmpPaint;
1075 tmpPaint.setAlpha(alpha);
1076 return this->saveLayer(bounds, &tmpPaint, flags);
1077 }
1078}
1079
reed@android.com8a1c16f2008-12-17 15:59:43 +00001080void SkCanvas::internalRestore() {
1081 SkASSERT(fMCStack.count() != 0);
1082
1083 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001084 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001085
reed687fa1c2015-04-07 08:00:56 -07001086 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001087
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001088 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001089 DeviceCM* layer = fMCRec->fLayer; // may be null
1090 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1091 fMCRec->fLayer = NULL;
1092
1093 // now do the normal restore()
1094 fMCRec->~MCRec(); // balanced in save()
1095 fMCStack.pop_back();
1096 fMCRec = (MCRec*)fMCStack.back();
1097
1098 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1099 since if we're being recorded, we don't want to record this (the
1100 recorder will have already recorded the restore).
1101 */
bsalomon49f085d2014-09-05 13:34:00 -07001102 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001103 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001104 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001105 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001106 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001107 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001108 fDeviceCMDirty = true;
reedb679ca82015-04-07 04:40:48 -07001109 SkDELETE(layer);
1110 } else {
1111 // we're at the root
reeda499f902015-05-01 09:34:31 -07001112 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001113 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001114 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001115 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001116}
1117
reed4a8126e2014-09-22 07:29:03 -07001118SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1119 if (NULL == props) {
1120 props = &fProps;
1121 }
1122 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001123}
1124
reed4a8126e2014-09-22 07:29:03 -07001125SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001126 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001127 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001128}
1129
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001130SkImageInfo SkCanvas::imageInfo() const {
1131 SkBaseDevice* dev = this->getDevice();
1132 if (dev) {
1133 return dev->imageInfo();
1134 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001135 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001136 }
1137}
1138
1139const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
reed884e97c2015-05-26 11:31:54 -07001140 SkPixmap pmap;
1141 if (!this->onPeekPixels(&pmap)) {
1142 return NULL;
1143 }
1144 if (info) {
1145 *info = pmap.info();
1146 }
1147 if (rowBytes) {
1148 *rowBytes = pmap.rowBytes();
1149 }
1150 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001151}
1152
reed884e97c2015-05-26 11:31:54 -07001153bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001154 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001155 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001156}
1157
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001158void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001159 SkPixmap pmap;
1160 if (!this->onAccessTopLayerPixels(&pmap)) {
1161 return NULL;
1162 }
1163 if (info) {
1164 *info = pmap.info();
1165 }
1166 if (rowBytes) {
1167 *rowBytes = pmap.rowBytes();
1168 }
1169 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001170 *origin = this->getTopDevice(false)->getOrigin();
1171 }
reed884e97c2015-05-26 11:31:54 -07001172 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001173}
1174
reed884e97c2015-05-26 11:31:54 -07001175bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001176 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001177 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001178}
1179
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001180SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1181 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1182 if (NULL == fAddr) {
1183 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001184 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001185 return; // failure, fAddr is NULL
1186 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001187 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1188 return; // failure, fAddr is NULL
1189 }
1190 fAddr = fBitmap.getPixels();
1191 fRowBytes = fBitmap.rowBytes();
1192 }
1193 SkASSERT(fAddr); // success
1194}
1195
1196bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1197 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001198 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001199 } else {
1200 bitmap->reset();
1201 return false;
1202 }
1203}
1204
reed@android.com8a1c16f2008-12-17 15:59:43 +00001205/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001206void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001207 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001208 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001209 return;
1210 }
1211
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001212 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001213 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001214 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001215 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001216
1217 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001218
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001219 SkRect storage;
1220 const SkRect* bounds = NULL;
1221 if (paint && paint->canComputeFastBounds()) {
1222 bitmap.getBounds(&storage);
1223 matrix.mapRect(&storage);
1224 bounds = &paint->computeFastBounds(storage, &storage);
1225 }
1226
1227 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001228
1229 while (iter.next()) {
1230 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1231 }
1232
1233 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001234}
1235
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001236void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001237 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001238 SkPaint tmp;
1239 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240 paint = &tmp;
1241 }
reed@google.com4b226022011-01-11 18:32:13 +00001242
reed@google.com8926b162012-03-23 15:36:36 +00001243 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001244 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001245 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001246 paint = &looper.paint();
1247 SkImageFilter* filter = paint->getImageFilter();
1248 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001249 if (filter && !dstDev->canHandleImageFilter(filter)) {
robertphillipsefbffed2015-06-22 12:06:08 -07001250 SkImageFilter::Proxy proxy(dstDev);
reed@google.com76dd2772012-01-05 21:15:07 +00001251 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001252 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001253 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001254 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001255 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001256 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001257 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001258 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001259 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001260 SkPaint tmpUnfiltered(*paint);
1261 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001262 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1263 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001264 }
reed61f501f2015-04-29 08:34:00 -07001265 } else if (deviceIsBitmapDevice) {
reed9572a102015-05-26 19:22:17 -07001266 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
reed61f501f2015-04-29 08:34:00 -07001267 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001268 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001269 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001270 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001271 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001272 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001273}
1274
reed41af9662015-01-05 07:49:08 -08001275void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001276 if (gTreatSpriteAsBitmap) {
1277 this->save();
1278 this->resetMatrix();
1279 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1280 this->restore();
1281 return;
1282 }
1283
danakj9881d632014-11-26 12:41:06 -08001284 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001285 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001286 return;
1287 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001288 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001289
reed@google.com8926b162012-03-23 15:36:36 +00001290 SkPaint tmp;
1291 if (NULL == paint) {
1292 paint = &tmp;
1293 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001294
reed@google.com8926b162012-03-23 15:36:36 +00001295 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001296
reed@google.com8926b162012-03-23 15:36:36 +00001297 while (iter.next()) {
1298 paint = &looper.paint();
1299 SkImageFilter* filter = paint->getImageFilter();
1300 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1301 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
robertphillipsefbffed2015-06-22 12:06:08 -07001302 SkImageFilter::Proxy proxy(iter.fDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001303 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001304 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001305 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001306 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001307 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001308 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001309 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001310 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001311 SkPaint tmpUnfiltered(*paint);
1312 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001313 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001314 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001315 }
1316 } else {
1317 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1318 }
1319 }
1320 LOOPER_END
1321}
1322
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001324void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001325 SkMatrix m;
1326 m.setTranslate(dx, dy);
1327 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328}
1329
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001330void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001331 SkMatrix m;
1332 m.setScale(sx, sy);
1333 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001334}
1335
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001336void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001337 SkMatrix m;
1338 m.setRotate(degrees);
1339 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340}
1341
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001342void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001343 SkMatrix m;
1344 m.setSkew(sx, sy);
1345 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001346}
1347
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001348void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001349 if (matrix.isIdentity()) {
1350 return;
1351 }
1352
reed2ff1fce2014-12-11 07:07:37 -08001353 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001354 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001355 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001356 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001357
1358 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001359}
1360
reed86a17e72015-05-14 12:25:22 -07001361void SkCanvas::setMatrix(const SkMatrix& matrix) {
1362 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001363 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001364 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001365 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001366 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001367}
1368
reed@android.com8a1c16f2008-12-17 15:59:43 +00001369void SkCanvas::resetMatrix() {
1370 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001371
reed@android.com8a1c16f2008-12-17 15:59:43 +00001372 matrix.reset();
1373 this->setMatrix(matrix);
1374}
1375
1376//////////////////////////////////////////////////////////////////////////////
1377
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001378void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001379 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001380 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1381 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001382}
1383
1384void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001385#ifdef SK_ENABLE_CLIP_QUICKREJECT
1386 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001387 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001388 return false;
1389 }
1390
reed@google.com3b3e8952012-08-16 20:53:31 +00001391 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001392 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001393 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001394
reed687fa1c2015-04-07 08:00:56 -07001395 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001396 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001397 }
1398 }
1399#endif
1400
reed@google.com5c3d1472011-02-22 19:12:23 +00001401 AutoValidateClip avc(this);
1402
reed@android.com8a1c16f2008-12-17 15:59:43 +00001403 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001404 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001405 if (!fAllowSoftClip) {
1406 edgeStyle = kHard_ClipEdgeStyle;
1407 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001408
reed1f836ee2014-07-07 07:49:34 -07001409 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001410 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001411 // the matrix. This means we don't have to a) make a path, and b) tell
1412 // the region code to scan-convert the path, only to discover that it
1413 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001414 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415
reed1f836ee2014-07-07 07:49:34 -07001416 fMCRec->fMatrix.mapRect(&r, rect);
reed687fa1c2015-04-07 08:00:56 -07001417 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001418 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001419 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001420 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001421 // and clip against that, since it can handle any matrix. However, to
1422 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1423 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424 SkPath path;
1425
1426 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001427 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001428 }
1429}
1430
reed73e714e2014-09-04 09:02:23 -07001431static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1432 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001433 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001434}
1435
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001436void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001437 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001438 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001439 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001440 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1441 } else {
1442 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001443 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001444}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001445
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001446void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001447 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001448 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001449 AutoValidateClip avc(this);
1450
1451 fDeviceCMDirty = true;
1452 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001453 if (!fAllowSoftClip) {
1454 edgeStyle = kHard_ClipEdgeStyle;
1455 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001456
reed687fa1c2015-04-07 08:00:56 -07001457 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001458
1459 SkPath devPath;
1460 devPath.addRRect(transformedRRect);
1461
reed73e714e2014-09-04 09:02:23 -07001462 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001463 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001464 }
1465
1466 SkPath path;
1467 path.addRRect(rrect);
1468 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001469 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001470}
1471
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001472void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001473 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001474 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1475 SkRect r;
1476 if (!path.isInverseFillType() && path.isRect(&r)) {
1477 this->onClipRect(r, op, edgeStyle);
1478 } else {
1479 this->onClipPath(path, op, edgeStyle);
1480 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001481}
1482
1483void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001484#ifdef SK_ENABLE_CLIP_QUICKREJECT
1485 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001486 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001487 return false;
1488 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001489
reed@google.com3b3e8952012-08-16 20:53:31 +00001490 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001491 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001492 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001493
reed687fa1c2015-04-07 08:00:56 -07001494 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001495 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001496 }
1497 }
1498#endif
1499
reed@google.com5c3d1472011-02-22 19:12:23 +00001500 AutoValidateClip avc(this);
1501
reed@android.com8a1c16f2008-12-17 15:59:43 +00001502 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001503 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001504 if (!fAllowSoftClip) {
1505 edgeStyle = kHard_ClipEdgeStyle;
1506 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001507
1508 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001509 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001510
reed@google.comfe701122011-11-08 19:41:23 +00001511 // Check if the transfomation, or the original path itself
1512 // made us empty. Note this can also happen if we contained NaN
1513 // values. computing the bounds detects this, and will set our
1514 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1515 if (devPath.getBounds().isEmpty()) {
1516 // resetting the path will remove any NaN or other wanky values
1517 // that might upset our scan converter.
1518 devPath.reset();
1519 }
1520
reed@google.com5c3d1472011-02-22 19:12:23 +00001521 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001522 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001523
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001524 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001525 bool clipIsAA = getClipStack()->asPath(&devPath);
1526 if (clipIsAA) {
1527 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001528 }
fmalita1a481fe2015-02-04 07:39:34 -08001529
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001530 op = SkRegion::kReplace_Op;
1531 }
1532
reed73e714e2014-09-04 09:02:23 -07001533 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001534}
1535
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001536void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001537 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001538 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001539}
1540
1541void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001542 AutoValidateClip avc(this);
1543
reed@android.com8a1c16f2008-12-17 15:59:43 +00001544 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001545 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001546
reed@google.com5c3d1472011-02-22 19:12:23 +00001547 // todo: signal fClipStack that we have a region, and therefore (I guess)
1548 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001549 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001550
reed1f836ee2014-07-07 07:49:34 -07001551 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001552}
1553
reed@google.com819c9212011-02-23 18:56:55 +00001554#ifdef SK_DEBUG
1555void SkCanvas::validateClip() const {
1556 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001557 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001558 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001559 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001560 return;
1561 }
1562
reed@google.com819c9212011-02-23 18:56:55 +00001563 SkIRect ir;
1564 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001565 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001566
reed687fa1c2015-04-07 08:00:56 -07001567 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001568 const SkClipStack::Element* element;
1569 while ((element = iter.next()) != NULL) {
1570 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001571 case SkClipStack::Element::kRect_Type:
1572 element->getRect().round(&ir);
1573 tmpClip.op(ir, element->getOp());
1574 break;
1575 case SkClipStack::Element::kEmpty_Type:
1576 tmpClip.setEmpty();
1577 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001578 default: {
1579 SkPath path;
1580 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001581 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001582 break;
1583 }
reed@google.com819c9212011-02-23 18:56:55 +00001584 }
1585 }
reed@google.com819c9212011-02-23 18:56:55 +00001586}
1587#endif
1588
reed@google.com90c07ea2012-04-13 13:50:27 +00001589void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001590 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001591 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001592
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001593 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001594 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001595 }
1596}
1597
reed@google.com5c3d1472011-02-22 19:12:23 +00001598///////////////////////////////////////////////////////////////////////////////
1599
reed@google.com754de5f2014-02-24 19:38:20 +00001600bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001601 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001602}
1603
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001604bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001605 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001606}
1607
reed@google.com3b3e8952012-08-16 20:53:31 +00001608bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001609 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001610 return true;
1611
reed1f836ee2014-07-07 07:49:34 -07001612 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001613 return true;
1614 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001615
reed1f836ee2014-07-07 07:49:34 -07001616 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001617 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001618 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001619 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001620 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001621 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001622
reed@android.coma380ae42009-07-21 01:17:02 +00001623 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001624 // TODO: should we use | instead, or compare all 4 at once?
1625 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001626 return true;
1627 }
reed@google.comc0784db2013-12-13 21:16:12 +00001628 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001629 return true;
1630 }
1631 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001632 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001633}
1634
reed@google.com3b3e8952012-08-16 20:53:31 +00001635bool SkCanvas::quickReject(const SkPath& path) const {
1636 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001637}
1638
reed@google.com3b3e8952012-08-16 20:53:31 +00001639bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001640 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001641 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001642 return false;
1643 }
1644
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001645 SkMatrix inverse;
1646 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001647 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001648 if (bounds) {
1649 bounds->setEmpty();
1650 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001651 return false;
1652 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001653
bsalomon49f085d2014-09-05 13:34:00 -07001654 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001655 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001656 // adjust it outwards in case we are antialiasing
1657 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001658
reed@google.com8f4d2302013-12-17 16:44:46 +00001659 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1660 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001661 inverse.mapRect(bounds, r);
1662 }
1663 return true;
1664}
1665
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001666bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001667 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001668 if (clip.isEmpty()) {
1669 if (bounds) {
1670 bounds->setEmpty();
1671 }
1672 return false;
1673 }
1674
bsalomon49f085d2014-09-05 13:34:00 -07001675 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001676 *bounds = clip.getBounds();
1677 }
1678 return true;
1679}
1680
reed@android.com8a1c16f2008-12-17 15:59:43 +00001681const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001682 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001683}
1684
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001685const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001686 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001687}
1688
reed@google.com9c135db2014-03-12 18:28:35 +00001689GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1690 SkBaseDevice* dev = this->getTopDevice();
1691 return dev ? dev->accessRenderTarget() : NULL;
1692}
1693
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001694GrContext* SkCanvas::getGrContext() {
1695#if SK_SUPPORT_GPU
1696 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001697 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001698 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001699 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001700 return renderTarget->getContext();
1701 }
1702 }
1703#endif
1704
1705 return NULL;
1706
1707}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001708
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001709void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1710 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001711 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001712 if (outer.isEmpty()) {
1713 return;
1714 }
1715 if (inner.isEmpty()) {
1716 this->drawRRect(outer, paint);
1717 return;
1718 }
1719
1720 // We don't have this method (yet), but technically this is what we should
1721 // be able to assert...
1722 // SkASSERT(outer.contains(inner));
1723 //
1724 // For now at least check for containment of bounds
1725 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1726
1727 this->onDrawDRRect(outer, inner, paint);
1728}
1729
reed41af9662015-01-05 07:49:08 -08001730// These need to stop being virtual -- clients need to override the onDraw... versions
1731
1732void SkCanvas::drawPaint(const SkPaint& paint) {
1733 this->onDrawPaint(paint);
1734}
1735
1736void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1737 this->onDrawRect(r, paint);
1738}
1739
1740void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1741 this->onDrawOval(r, paint);
1742}
1743
1744void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1745 this->onDrawRRect(rrect, paint);
1746}
1747
1748void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1749 this->onDrawPoints(mode, count, pts, paint);
1750}
1751
1752void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1753 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1754 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1755 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1756 indices, indexCount, paint);
1757}
1758
1759void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1760 this->onDrawPath(path, paint);
1761}
1762
reeda85d4d02015-05-06 12:56:48 -07001763void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1764 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001765}
1766
1767void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1768 const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07001769 if (dst.isEmpty()) {
1770 return;
1771 }
reed41af9662015-01-05 07:49:08 -08001772 this->onDrawImageRect(image, src, dst, paint);
1773}
1774
reed4c21dc52015-06-25 12:32:03 -07001775void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1776 const SkPaint* paint) {
1777 if (dst.isEmpty()) {
1778 return;
1779 }
1780 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
1781 this->drawImageRect(image, NULL, dst, paint);
1782 }
1783 this->onDrawImageNine(image, center, dst, paint);
1784}
1785
reed41af9662015-01-05 07:49:08 -08001786void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001787 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001788 return;
1789 }
reed41af9662015-01-05 07:49:08 -08001790 this->onDrawBitmap(bitmap, dx, dy, paint);
1791}
1792
1793void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1794 const SkPaint* paint, DrawBitmapRectFlags flags) {
reed4c21dc52015-06-25 12:32:03 -07001795 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001796 return;
1797 }
reed41af9662015-01-05 07:49:08 -08001798 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1799}
1800
1801void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1802 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001803 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001804 return;
1805 }
reed4c21dc52015-06-25 12:32:03 -07001806 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
1807 this->drawBitmapRectToRect(bitmap, NULL, dst, paint);
1808 }
reed41af9662015-01-05 07:49:08 -08001809 this->onDrawBitmapNine(bitmap, center, dst, paint);
1810}
1811
1812void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001813 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001814 return;
1815 }
reed41af9662015-01-05 07:49:08 -08001816 this->onDrawSprite(bitmap, left, top, paint);
1817}
1818
reed71c3c762015-06-24 10:29:17 -07001819void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1820 const SkColor colors[], int count, SkXfermode::Mode mode,
1821 const SkRect* cull, const SkPaint* paint) {
1822 if (count <= 0) {
1823 return;
1824 }
1825 SkASSERT(atlas);
1826 SkASSERT(xform);
1827 SkASSERT(tex);
1828 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1829}
1830
reed@android.com8a1c16f2008-12-17 15:59:43 +00001831//////////////////////////////////////////////////////////////////////////////
1832// These are the virtual drawing methods
1833//////////////////////////////////////////////////////////////////////////////
1834
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001835void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001836 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001837 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1838 }
1839}
1840
reed41af9662015-01-05 07:49:08 -08001841void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001842 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001843 this->internalDrawPaint(paint);
1844}
1845
1846void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001847 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001848
1849 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001850 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001851 }
1852
reed@google.com4e2b3d32011-04-07 14:18:59 +00001853 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001854}
1855
reed41af9662015-01-05 07:49:08 -08001856void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1857 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001858 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001859 if ((long)count <= 0) {
1860 return;
1861 }
1862
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001863 SkRect r, storage;
1864 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001865 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001866 // special-case 2 points (common for drawing a single line)
1867 if (2 == count) {
1868 r.set(pts[0], pts[1]);
1869 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001870 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001871 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001872 bounds = &paint.computeFastStrokeBounds(r, &storage);
1873 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001874 return;
1875 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001876 }
reed@google.coma584aed2012-05-16 14:06:02 +00001877
reed@android.com8a1c16f2008-12-17 15:59:43 +00001878 SkASSERT(pts != NULL);
1879
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001880 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001881
reed@android.com8a1c16f2008-12-17 15:59:43 +00001882 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001883 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001884 }
reed@google.com4b226022011-01-11 18:32:13 +00001885
reed@google.com4e2b3d32011-04-07 14:18:59 +00001886 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001887}
1888
reed41af9662015-01-05 07:49:08 -08001889void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001890 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001891 SkRect storage;
1892 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001893 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001894 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1895 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1896 SkRect tmp(r);
1897 tmp.sort();
1898
1899 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001900 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001901 return;
1902 }
1903 }
reed@google.com4b226022011-01-11 18:32:13 +00001904
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001905 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001906
1907 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001908 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001909 }
1910
reed@google.com4e2b3d32011-04-07 14:18:59 +00001911 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001912}
1913
reed41af9662015-01-05 07:49:08 -08001914void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001915 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001916 SkRect storage;
1917 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001918 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001919 bounds = &paint.computeFastBounds(oval, &storage);
1920 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001921 return;
1922 }
1923 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001924
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001925 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001926
1927 while (iter.next()) {
1928 iter.fDevice->drawOval(iter, oval, looper.paint());
1929 }
1930
1931 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001932}
1933
reed41af9662015-01-05 07:49:08 -08001934void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001935 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001936 SkRect storage;
1937 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001938 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001939 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1940 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001941 return;
1942 }
1943 }
1944
1945 if (rrect.isRect()) {
1946 // call the non-virtual version
1947 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001948 return;
1949 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001950 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001951 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1952 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001953 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001954
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001955 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001956
1957 while (iter.next()) {
1958 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1959 }
1960
1961 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001962}
1963
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001964void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1965 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001966 SkRect storage;
1967 const SkRect* bounds = NULL;
1968 if (paint.canComputeFastBounds()) {
1969 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1970 if (this->quickReject(*bounds)) {
1971 return;
1972 }
1973 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001974
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001975 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001976
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001977 while (iter.next()) {
1978 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1979 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001980
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001981 LOOPER_END
1982}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001983
reed41af9662015-01-05 07:49:08 -08001984void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001985 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001986 if (!path.isFinite()) {
1987 return;
1988 }
1989
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001990 SkRect storage;
1991 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001992 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001993 const SkRect& pathBounds = path.getBounds();
1994 bounds = &paint.computeFastBounds(pathBounds, &storage);
1995 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001996 return;
1997 }
1998 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001999
2000 const SkRect& r = path.getBounds();
2001 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002002 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002003 this->internalDrawPaint(paint);
2004 }
2005 return;
2006 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002007
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002008 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002009
2010 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002011 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002012 }
2013
reed@google.com4e2b3d32011-04-07 14:18:59 +00002014 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002015}
2016
reeda85d4d02015-05-06 12:56:48 -07002017void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002018 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002019 SkRect bounds = SkRect::MakeXYWH(x, y,
2020 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
2021 if (NULL == paint || paint->canComputeFastBounds()) {
2022 if (paint) {
2023 paint->computeFastBounds(bounds, &bounds);
2024 }
2025 if (this->quickReject(bounds)) {
2026 return;
2027 }
2028 }
2029
2030 SkLazyPaint lazy;
2031 if (NULL == paint) {
2032 paint = lazy.init();
2033 }
2034
2035 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds)
2036
2037 while (iter.next()) {
2038 iter.fDevice->drawImage(iter, image, x, y, looper.paint());
2039 }
2040
2041 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002042}
2043
reed41af9662015-01-05 07:49:08 -08002044void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2045 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002046 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
reeda85d4d02015-05-06 12:56:48 -07002047 SkRect storage;
2048 const SkRect* bounds = &dst;
2049 if (NULL == paint || paint->canComputeFastBounds()) {
2050 if (paint) {
2051 bounds = &paint->computeFastBounds(dst, &storage);
2052 }
2053 if (this->quickReject(*bounds)) {
2054 return;
2055 }
2056 }
2057 SkLazyPaint lazy;
2058 if (NULL == paint) {
2059 paint = lazy.init();
2060 }
2061
2062 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2063
2064 while (iter.next()) {
2065 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint());
2066 }
2067
2068 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002069}
2070
reed41af9662015-01-05 07:49:08 -08002071void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002072 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002073 SkDEBUGCODE(bitmap.validate();)
2074
reed@google.com3d608122011-11-21 15:16:16 +00002075 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002076 SkRect bounds = {
2077 x, y,
2078 x + SkIntToScalar(bitmap.width()),
2079 y + SkIntToScalar(bitmap.height())
2080 };
2081 if (paint) {
2082 (void)paint->computeFastBounds(bounds, &bounds);
2083 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002084 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002085 return;
2086 }
2087 }
reed@google.com4b226022011-01-11 18:32:13 +00002088
reed@android.com8a1c16f2008-12-17 15:59:43 +00002089 SkMatrix matrix;
2090 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00002091 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002092}
2093
reed@google.com9987ec32011-09-07 11:57:52 +00002094// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002095void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002096 const SkRect& dst, const SkPaint* paint,
2097 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002098 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002099 return;
2100 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002101
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002102 SkRect storage;
2103 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00002104 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002105 if (paint) {
2106 bounds = &paint->computeFastBounds(dst, &storage);
2107 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002108 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002109 return;
2110 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002111 }
reed@google.com3d608122011-11-21 15:16:16 +00002112
reed@google.com33535f32012-09-25 15:37:50 +00002113 SkLazyPaint lazy;
2114 if (NULL == paint) {
2115 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002116 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002117
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002118 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002119
reed@google.com33535f32012-09-25 15:37:50 +00002120 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002121 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00002122 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002123
reed@google.com33535f32012-09-25 15:37:50 +00002124 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002125}
2126
reed41af9662015-01-05 07:49:08 -08002127void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2128 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08002129 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002130 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002131 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00002132}
2133
reed4c21dc52015-06-25 12:32:03 -07002134void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2135 const SkPaint* paint) {
2136 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2137
2138 SkRect storage;
2139 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00002140 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00002141 if (paint) {
2142 bounds = &paint->computeFastBounds(dst, &storage);
2143 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002144 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002145 return;
2146 }
2147 }
reed4c21dc52015-06-25 12:32:03 -07002148
2149 SkLazyPaint lazy;
2150 if (NULL == paint) {
2151 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002152 }
reed4c21dc52015-06-25 12:32:03 -07002153
2154 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2155
2156 while (iter.next()) {
2157 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002158 }
reed4c21dc52015-06-25 12:32:03 -07002159
2160 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002161}
2162
reed41af9662015-01-05 07:49:08 -08002163void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2164 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002165 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002166 SkDEBUGCODE(bitmap.validate();)
2167
reed4c21dc52015-06-25 12:32:03 -07002168 SkRect storage;
2169 const SkRect* bounds = &dst;
2170 if (NULL == paint || paint->canComputeFastBounds()) {
2171 if (paint) {
2172 bounds = &paint->computeFastBounds(dst, &storage);
2173 }
2174 if (this->quickReject(*bounds)) {
2175 return;
2176 }
2177 }
2178
2179 SkLazyPaint lazy;
2180 if (NULL == paint) {
2181 paint = lazy.init();
2182 }
2183
2184 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2185
2186 while (iter.next()) {
2187 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2188 }
2189
2190 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002191}
2192
reed@google.comf67e4cf2011-03-15 20:56:58 +00002193class SkDeviceFilteredPaint {
2194public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002195 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002196 uint32_t filteredFlags = device->filterTextFlags(paint);
2197 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002198 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002199 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002200 fPaint = newPaint;
2201 } else {
2202 fPaint = &paint;
2203 }
2204 }
2205
reed@google.comf67e4cf2011-03-15 20:56:58 +00002206 const SkPaint& paint() const { return *fPaint; }
2207
2208private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002209 const SkPaint* fPaint;
2210 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002211};
2212
bungeman@google.com52c748b2011-08-22 21:30:43 +00002213void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2214 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002215 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002216 draw.fDevice->drawRect(draw, r, paint);
2217 } else {
2218 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002219 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002220 draw.fDevice->drawRect(draw, r, p);
2221 }
2222}
2223
2224void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2225 const char text[], size_t byteLength,
2226 SkScalar x, SkScalar y) {
2227 SkASSERT(byteLength == 0 || text != NULL);
2228
2229 // nothing to draw
2230 if (text == NULL || byteLength == 0 ||
2231 draw.fClip->isEmpty() ||
2232 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2233 return;
2234 }
2235
2236 SkScalar width = 0;
2237 SkPoint start;
2238
2239 start.set(0, 0); // to avoid warning
2240 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2241 SkPaint::kStrikeThruText_Flag)) {
2242 width = paint.measureText(text, byteLength);
2243
2244 SkScalar offsetX = 0;
2245 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2246 offsetX = SkScalarHalf(width);
2247 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2248 offsetX = width;
2249 }
2250 start.set(x - offsetX, y);
2251 }
2252
2253 if (0 == width) {
2254 return;
2255 }
2256
2257 uint32_t flags = paint.getFlags();
2258
2259 if (flags & (SkPaint::kUnderlineText_Flag |
2260 SkPaint::kStrikeThruText_Flag)) {
2261 SkScalar textSize = paint.getTextSize();
2262 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2263 SkRect r;
2264
2265 r.fLeft = start.fX;
2266 r.fRight = start.fX + width;
2267
2268 if (flags & SkPaint::kUnderlineText_Flag) {
2269 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2270 start.fY);
2271 r.fTop = offset;
2272 r.fBottom = offset + height;
2273 DrawRect(draw, paint, r, textSize);
2274 }
2275 if (flags & SkPaint::kStrikeThruText_Flag) {
2276 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2277 start.fY);
2278 r.fTop = offset;
2279 r.fBottom = offset + height;
2280 DrawRect(draw, paint, r, textSize);
2281 }
2282 }
2283}
2284
reed@google.come0d9ce82014-04-23 04:00:17 +00002285void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2286 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002287 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002288
2289 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002290 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002291 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002292 DrawTextDecorations(iter, dfp.paint(),
2293 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002294 }
2295
reed@google.com4e2b3d32011-04-07 14:18:59 +00002296 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002297}
2298
reed@google.come0d9ce82014-04-23 04:00:17 +00002299void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2300 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002301 SkPoint textOffset = SkPoint::Make(0, 0);
2302
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002303 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002304
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002306 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002307 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002308 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002309 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002310
reed@google.com4e2b3d32011-04-07 14:18:59 +00002311 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002312}
2313
reed@google.come0d9ce82014-04-23 04:00:17 +00002314void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2315 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002316
2317 SkPoint textOffset = SkPoint::Make(0, constY);
2318
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002319 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002320
reed@android.com8a1c16f2008-12-17 15:59:43 +00002321 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002322 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002323 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002324 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002325 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002326
reed@google.com4e2b3d32011-04-07 14:18:59 +00002327 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002328}
2329
reed@google.come0d9ce82014-04-23 04:00:17 +00002330void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2331 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002332 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002333
reed@android.com8a1c16f2008-12-17 15:59:43 +00002334 while (iter.next()) {
2335 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002336 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002337 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002338
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002339 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002340}
2341
fmalita00d5c2c2014-08-21 08:53:26 -07002342void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2343 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002344
fmalita85d5eb92015-03-04 11:20:12 -08002345 SkRect storage;
2346 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002347 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002348 storage = blob->bounds().makeOffset(x, y);
2349 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002350
fmalita85d5eb92015-03-04 11:20:12 -08002351 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002352 return;
2353 }
2354 }
2355
fmalita024f9962015-03-03 19:08:17 -08002356 // We cannot filter in the looper as we normally do, because the paint is
2357 // incomplete at this point (text-related attributes are embedded within blob run paints).
2358 SkDrawFilter* drawFilter = fMCRec->fFilter;
2359 fMCRec->fFilter = NULL;
2360
fmalita85d5eb92015-03-04 11:20:12 -08002361 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002362
fmalitaaa1b9122014-08-28 14:32:24 -07002363 while (iter.next()) {
2364 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002365 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002366 }
2367
fmalitaaa1b9122014-08-28 14:32:24 -07002368 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002369
2370 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002371}
2372
reed@google.come0d9ce82014-04-23 04:00:17 +00002373// These will become non-virtual, so they always call the (virtual) onDraw... method
2374void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2375 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002376 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002377 this->onDrawText(text, byteLength, x, y, paint);
2378}
2379void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2380 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002381 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002382 this->onDrawPosText(text, byteLength, pos, paint);
2383}
2384void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2385 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002386 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002387 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2388}
2389void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2390 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002391 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002392 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2393}
fmalita00d5c2c2014-08-21 08:53:26 -07002394void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2395 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002396 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002397 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002398 this->onDrawTextBlob(blob, x, y, paint);
2399 }
2400}
reed@google.come0d9ce82014-04-23 04:00:17 +00002401
reed41af9662015-01-05 07:49:08 -08002402void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2403 const SkPoint verts[], const SkPoint texs[],
2404 const SkColor colors[], SkXfermode* xmode,
2405 const uint16_t indices[], int indexCount,
2406 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002407 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002408 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002409
reed@android.com8a1c16f2008-12-17 15:59:43 +00002410 while (iter.next()) {
2411 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002412 colors, xmode, indices, indexCount,
2413 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002414 }
reed@google.com4b226022011-01-11 18:32:13 +00002415
reed@google.com4e2b3d32011-04-07 14:18:59 +00002416 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002417}
2418
dandovb3c9d1c2014-08-12 08:34:29 -07002419void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2420 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002421 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002422 if (NULL == cubics) {
2423 return;
2424 }
mtklein6cfa73a2014-08-13 13:33:49 -07002425
dandovecfff212014-08-04 10:02:00 -07002426 // Since a patch is always within the convex hull of the control points, we discard it when its
2427 // bounding rectangle is completely outside the current clip.
2428 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002429 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002430 if (this->quickReject(bounds)) {
2431 return;
2432 }
mtklein6cfa73a2014-08-13 13:33:49 -07002433
dandovb3c9d1c2014-08-12 08:34:29 -07002434 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2435}
2436
2437void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2438 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2439
dandovecfff212014-08-04 10:02:00 -07002440 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002441
dandovecfff212014-08-04 10:02:00 -07002442 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002443 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002444 }
mtklein6cfa73a2014-08-13 13:33:49 -07002445
dandovecfff212014-08-04 10:02:00 -07002446 LOOPER_END
2447}
2448
reed3cb38402015-02-06 08:36:15 -08002449void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002450 if (dr && !this->quickReject(dr->getBounds())) {
2451 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002452 }
2453}
2454
reed3cb38402015-02-06 08:36:15 -08002455void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002456 dr->draw(this);
2457}
2458
reed71c3c762015-06-24 10:29:17 -07002459void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2460 const SkColor colors[], int count, SkXfermode::Mode mode,
2461 const SkRect* cull, const SkPaint* paint) {
2462 if (cull && this->quickReject(*cull)) {
2463 return;
2464 }
2465
2466 SkPaint pnt;
2467 if (paint) {
2468 pnt = *paint;
2469 }
2470
2471 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, NULL)
2472 while (iter.next()) {
2473 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2474 }
2475 LOOPER_END
2476}
2477
reed@android.com8a1c16f2008-12-17 15:59:43 +00002478//////////////////////////////////////////////////////////////////////////////
2479// These methods are NOT virtual, and therefore must call back into virtual
2480// methods, rather than actually drawing themselves.
2481//////////////////////////////////////////////////////////////////////////////
2482
2483void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002484 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002485 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002486 SkPaint paint;
2487
2488 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002489 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002490 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002491 }
2492 this->drawPaint(paint);
2493}
2494
reed@android.com845fdac2009-06-23 03:01:32 +00002495void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002496 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002497 SkPaint paint;
2498
2499 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002500 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002501 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002502 }
2503 this->drawPaint(paint);
2504}
2505
2506void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002507 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002508 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002509
reed@android.com8a1c16f2008-12-17 15:59:43 +00002510 pt.set(x, y);
2511 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2512}
2513
2514void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002515 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002516 SkPoint pt;
2517 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002518
reed@android.com8a1c16f2008-12-17 15:59:43 +00002519 pt.set(x, y);
2520 paint.setColor(color);
2521 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2522}
2523
2524void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2525 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002526 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002527 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002528
reed@android.com8a1c16f2008-12-17 15:59:43 +00002529 pts[0].set(x0, y0);
2530 pts[1].set(x1, y1);
2531 this->drawPoints(kLines_PointMode, 2, pts, paint);
2532}
2533
2534void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2535 SkScalar right, SkScalar bottom,
2536 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002537 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002538 SkRect r;
2539
2540 r.set(left, top, right, bottom);
2541 this->drawRect(r, paint);
2542}
2543
2544void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2545 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002546 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002547 if (radius < 0) {
2548 radius = 0;
2549 }
2550
2551 SkRect r;
2552 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002553 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002554}
2555
2556void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2557 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002558 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002559 if (rx > 0 && ry > 0) {
2560 if (paint.canComputeFastBounds()) {
2561 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002562 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002563 return;
2564 }
2565 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002566 SkRRect rrect;
2567 rrect.setRectXY(r, rx, ry);
2568 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002569 } else {
2570 this->drawRect(r, paint);
2571 }
2572}
2573
reed@android.com8a1c16f2008-12-17 15:59:43 +00002574void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2575 SkScalar sweepAngle, bool useCenter,
2576 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002577 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002578 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2579 this->drawOval(oval, paint);
2580 } else {
2581 SkPath path;
2582 if (useCenter) {
2583 path.moveTo(oval.centerX(), oval.centerY());
2584 }
2585 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2586 if (useCenter) {
2587 path.close();
2588 }
2589 this->drawPath(path, paint);
2590 }
2591}
2592
2593void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2594 const SkPath& path, SkScalar hOffset,
2595 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002596 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002597 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002598
reed@android.com8a1c16f2008-12-17 15:59:43 +00002599 matrix.setTranslate(hOffset, vOffset);
2600 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2601}
2602
reed@android.comf76bacf2009-05-13 14:00:33 +00002603///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002604
2605/**
2606 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2607 * against the playback cost of recursing into the subpicture to get at its actual ops.
2608 *
2609 * For now we pick a conservatively small value, though measurement (and other heuristics like
2610 * the type of ops contained) may justify changing this value.
2611 */
2612#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002613
reedd5fa1a42014-08-09 11:08:05 -07002614void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002615 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002616 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002617 if (matrix && matrix->isIdentity()) {
2618 matrix = NULL;
2619 }
reed1c2c4412015-04-30 13:09:24 -07002620 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2621 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2622 picture->playback(this);
2623 } else {
2624 this->onDrawPicture(picture, matrix, paint);
2625 }
reedd5fa1a42014-08-09 11:08:05 -07002626 }
2627}
robertphillips9b14f262014-06-04 05:40:44 -07002628
reedd5fa1a42014-08-09 11:08:05 -07002629void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2630 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002631 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002632 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002633 // Canvas has to first give the device the opportunity to render
2634 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002635 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002636 return; // the device has rendered the entire picture
2637 }
2638 }
2639
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002640 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002641 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002642}
2643
reed@android.com8a1c16f2008-12-17 15:59:43 +00002644///////////////////////////////////////////////////////////////////////////////
2645///////////////////////////////////////////////////////////////////////////////
2646
2647SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002648 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002649
2650 SkASSERT(canvas);
2651
2652 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2653 fDone = !fImpl->next();
2654}
2655
2656SkCanvas::LayerIter::~LayerIter() {
2657 fImpl->~SkDrawIter();
2658}
2659
2660void SkCanvas::LayerIter::next() {
2661 fDone = !fImpl->next();
2662}
2663
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002664SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002665 return fImpl->getDevice();
2666}
2667
2668const SkMatrix& SkCanvas::LayerIter::matrix() const {
2669 return fImpl->getMatrix();
2670}
2671
2672const SkPaint& SkCanvas::LayerIter::paint() const {
2673 const SkPaint* paint = fImpl->getPaint();
2674 if (NULL == paint) {
2675 paint = &fDefaultPaint;
2676 }
2677 return *paint;
2678}
2679
2680const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2681int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2682int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002683
2684///////////////////////////////////////////////////////////////////////////////
2685
fmalitac3b589a2014-06-05 12:40:07 -07002686SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002687
2688///////////////////////////////////////////////////////////////////////////////
2689
2690static bool supported_for_raster_canvas(const SkImageInfo& info) {
2691 switch (info.alphaType()) {
2692 case kPremul_SkAlphaType:
2693 case kOpaque_SkAlphaType:
2694 break;
2695 default:
2696 return false;
2697 }
2698
2699 switch (info.colorType()) {
2700 case kAlpha_8_SkColorType:
2701 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002702 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002703 break;
2704 default:
2705 return false;
2706 }
2707
2708 return true;
2709}
2710
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002711SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2712 if (!supported_for_raster_canvas(info)) {
2713 return NULL;
2714 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002715
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002716 SkBitmap bitmap;
2717 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2718 return NULL;
2719 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002720 return SkNEW_ARGS(SkCanvas, (bitmap));
2721}
reedd5fa1a42014-08-09 11:08:05 -07002722
2723///////////////////////////////////////////////////////////////////////////////
2724
2725SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002726 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002727 : fCanvas(canvas)
2728 , fSaveCount(canvas->getSaveCount())
2729{
bsalomon49f085d2014-09-05 13:34:00 -07002730 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002731 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002732 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002733 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002734 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002735 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002736 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002737 canvas->save();
2738 }
mtklein6cfa73a2014-08-13 13:33:49 -07002739
bsalomon49f085d2014-09-05 13:34:00 -07002740 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002741 canvas->concat(*matrix);
2742 }
2743}
2744
2745SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2746 fCanvas->restoreToCount(fSaveCount);
2747}