blob: 35551e7e9a1e88b64537369c190fbcfd4d0b9ec2 [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,
reeda5517e22015-07-14 10:54:12 -07001768 const SkPaint* paint, SrcRectConstraint constraint) {
reeda85d4d02015-05-06 12:56:48 -07001769 if (dst.isEmpty()) {
1770 return;
1771 }
reeda5517e22015-07-14 10:54:12 -07001772 this->onDrawImageRect(image, src, dst, paint SRC_RECT_CONSTRAINT_ARG(constraint));
reed41af9662015-01-05 07:49:08 -08001773}
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 }
reeda5517e22015-07-14 10:54:12 -07001798 this->onDrawBitmapRect(bitmap, src, dst, paint, (SK_VIRTUAL_CONSTRAINT_TYPE)flags);
1799}
1800
1801void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1802 const SkPaint* paint, SrcRectConstraint constraint) {
1803 if (bitmap.drawsNothing() || dst.isEmpty()) {
1804 return;
1805 }
1806 this->onDrawBitmapRect(bitmap, src, dst, paint, (SK_VIRTUAL_CONSTRAINT_TYPE)constraint);
reed41af9662015-01-05 07:49:08 -08001807}
1808
1809void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1810 const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001811 if (bitmap.drawsNothing() || dst.isEmpty()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001812 return;
1813 }
reed4c21dc52015-06-25 12:32:03 -07001814 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
reeda5517e22015-07-14 10:54:12 -07001815 this->drawBitmapRect(bitmap, dst, paint);
reed4c21dc52015-06-25 12:32:03 -07001816 }
reed41af9662015-01-05 07:49:08 -08001817 this->onDrawBitmapNine(bitmap, center, dst, paint);
1818}
1819
1820void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
reed4c21dc52015-06-25 12:32:03 -07001821 if (bitmap.drawsNothing()) {
tomhudson2df6fd62015-04-09 09:20:19 -07001822 return;
1823 }
reed41af9662015-01-05 07:49:08 -08001824 this->onDrawSprite(bitmap, left, top, paint);
1825}
1826
reed71c3c762015-06-24 10:29:17 -07001827void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1828 const SkColor colors[], int count, SkXfermode::Mode mode,
1829 const SkRect* cull, const SkPaint* paint) {
1830 if (count <= 0) {
1831 return;
1832 }
1833 SkASSERT(atlas);
1834 SkASSERT(xform);
1835 SkASSERT(tex);
1836 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1837}
1838
reed@android.com8a1c16f2008-12-17 15:59:43 +00001839//////////////////////////////////////////////////////////////////////////////
1840// These are the virtual drawing methods
1841//////////////////////////////////////////////////////////////////////////////
1842
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001843void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001844 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001845 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1846 }
1847}
1848
reed41af9662015-01-05 07:49:08 -08001849void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001850 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001851 this->internalDrawPaint(paint);
1852}
1853
1854void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001855 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001856
1857 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001858 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001859 }
1860
reed@google.com4e2b3d32011-04-07 14:18:59 +00001861 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001862}
1863
reed41af9662015-01-05 07:49:08 -08001864void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1865 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001866 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001867 if ((long)count <= 0) {
1868 return;
1869 }
1870
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001871 SkRect r, storage;
1872 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001873 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001874 // special-case 2 points (common for drawing a single line)
1875 if (2 == count) {
1876 r.set(pts[0], pts[1]);
1877 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001878 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001879 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001880 bounds = &paint.computeFastStrokeBounds(r, &storage);
1881 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001882 return;
1883 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001884 }
reed@google.coma584aed2012-05-16 14:06:02 +00001885
reed@android.com8a1c16f2008-12-17 15:59:43 +00001886 SkASSERT(pts != NULL);
1887
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001888 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001889
reed@android.com8a1c16f2008-12-17 15:59:43 +00001890 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001891 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001892 }
reed@google.com4b226022011-01-11 18:32:13 +00001893
reed@google.com4e2b3d32011-04-07 14:18:59 +00001894 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001895}
1896
reed41af9662015-01-05 07:49:08 -08001897void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001898 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001899 SkRect storage;
1900 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001901 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001902 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1903 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1904 SkRect tmp(r);
1905 tmp.sort();
1906
1907 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001908 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001909 return;
1910 }
1911 }
reed@google.com4b226022011-01-11 18:32:13 +00001912
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001913 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001914
1915 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001916 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001917 }
1918
reed@google.com4e2b3d32011-04-07 14:18:59 +00001919 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001920}
1921
reed41af9662015-01-05 07:49:08 -08001922void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001923 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001924 SkRect storage;
1925 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001926 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001927 bounds = &paint.computeFastBounds(oval, &storage);
1928 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001929 return;
1930 }
1931 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001932
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001933 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001934
1935 while (iter.next()) {
1936 iter.fDevice->drawOval(iter, oval, looper.paint());
1937 }
1938
1939 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001940}
1941
reed41af9662015-01-05 07:49:08 -08001942void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001943 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001944 SkRect storage;
1945 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001946 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001947 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1948 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001949 return;
1950 }
1951 }
1952
1953 if (rrect.isRect()) {
1954 // call the non-virtual version
1955 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001956 return;
1957 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001958 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001959 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1960 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001961 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001962
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001963 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001964
1965 while (iter.next()) {
1966 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1967 }
1968
1969 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001970}
1971
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001972void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1973 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001974 SkRect storage;
1975 const SkRect* bounds = NULL;
1976 if (paint.canComputeFastBounds()) {
1977 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1978 if (this->quickReject(*bounds)) {
1979 return;
1980 }
1981 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001982
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001983 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001984
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001985 while (iter.next()) {
1986 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1987 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001988
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001989 LOOPER_END
1990}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001991
reed41af9662015-01-05 07:49:08 -08001992void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001993 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001994 if (!path.isFinite()) {
1995 return;
1996 }
1997
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001998 SkRect storage;
1999 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002000 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002001 const SkRect& pathBounds = path.getBounds();
2002 bounds = &paint.computeFastBounds(pathBounds, &storage);
2003 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002004 return;
2005 }
2006 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00002007
2008 const SkRect& r = path.getBounds();
2009 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00002010 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00002011 this->internalDrawPaint(paint);
2012 }
2013 return;
2014 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002015
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002016 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002017
2018 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002019 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002020 }
2021
reed@google.com4e2b3d32011-04-07 14:18:59 +00002022 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002023}
2024
reeda85d4d02015-05-06 12:56:48 -07002025void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002026 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07002027 SkRect bounds = SkRect::MakeXYWH(x, y,
2028 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
2029 if (NULL == paint || paint->canComputeFastBounds()) {
2030 if (paint) {
2031 paint->computeFastBounds(bounds, &bounds);
2032 }
2033 if (this->quickReject(bounds)) {
2034 return;
2035 }
2036 }
2037
2038 SkLazyPaint lazy;
2039 if (NULL == paint) {
2040 paint = lazy.init();
2041 }
2042
2043 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds)
2044
2045 while (iter.next()) {
2046 iter.fDevice->drawImage(iter, image, x, y, looper.paint());
2047 }
2048
2049 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002050}
2051
reed41af9662015-01-05 07:49:08 -08002052void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002053 const SkPaint* paint SRC_RECT_CONSTRAINT_PARAM(constraint)) {
danakj9881d632014-11-26 12:41:06 -08002054 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
reeda5517e22015-07-14 10:54:12 -07002055 SRC_RECT_CONSTRAINT_LOCAL_DEFAULT(constraint)
reeda85d4d02015-05-06 12:56:48 -07002056 SkRect storage;
2057 const SkRect* bounds = &dst;
2058 if (NULL == paint || paint->canComputeFastBounds()) {
2059 if (paint) {
2060 bounds = &paint->computeFastBounds(dst, &storage);
2061 }
2062 if (this->quickReject(*bounds)) {
2063 return;
2064 }
2065 }
2066 SkLazyPaint lazy;
2067 if (NULL == paint) {
2068 paint = lazy.init();
2069 }
2070
2071 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2072
2073 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002074 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
reeda85d4d02015-05-06 12:56:48 -07002075 }
2076
2077 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002078}
2079
reed41af9662015-01-05 07:49:08 -08002080void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002081 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002082 SkDEBUGCODE(bitmap.validate();)
2083
reed@google.com3d608122011-11-21 15:16:16 +00002084 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002085 SkRect bounds = {
2086 x, y,
2087 x + SkIntToScalar(bitmap.width()),
2088 y + SkIntToScalar(bitmap.height())
2089 };
2090 if (paint) {
2091 (void)paint->computeFastBounds(bounds, &bounds);
2092 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002093 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002094 return;
2095 }
2096 }
reed@google.com4b226022011-01-11 18:32:13 +00002097
reed@android.com8a1c16f2008-12-17 15:59:43 +00002098 SkMatrix matrix;
2099 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00002100 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002101}
2102
reed@google.com9987ec32011-09-07 11:57:52 +00002103// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002104void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002105 const SkRect& dst, const SkPaint* paint,
reeda5517e22015-07-14 10:54:12 -07002106 SrcRectConstraint constraint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002107 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002108 return;
2109 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002110
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002111 SkRect storage;
2112 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00002113 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002114 if (paint) {
2115 bounds = &paint->computeFastBounds(dst, &storage);
2116 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002117 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002118 return;
2119 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002120 }
reed@google.com3d608122011-11-21 15:16:16 +00002121
reed@google.com33535f32012-09-25 15:37:50 +00002122 SkLazyPaint lazy;
2123 if (NULL == paint) {
2124 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002125 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002126
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002127 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002128
reed@google.com33535f32012-09-25 15:37:50 +00002129 while (iter.next()) {
reeda5517e22015-07-14 10:54:12 -07002130 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(),
2131 (SK_VIRTUAL_CONSTRAINT_TYPE)constraint);
reed@android.comf2b98d62010-12-20 18:26:13 +00002132 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002133
reed@google.com33535f32012-09-25 15:37:50 +00002134 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002135}
2136
reed41af9662015-01-05 07:49:08 -08002137void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reeda5517e22015-07-14 10:54:12 -07002138 const SkPaint* paint, SK_VIRTUAL_CONSTRAINT_TYPE constraint) {
danakj9881d632014-11-26 12:41:06 -08002139 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002140 SkDEBUGCODE(bitmap.validate();)
reeda5517e22015-07-14 10:54:12 -07002141 this->internalDrawBitmapRect(bitmap, src, dst, paint, (SrcRectConstraint)constraint);
reed@google.com9987ec32011-09-07 11:57:52 +00002142}
2143
reed4c21dc52015-06-25 12:32:03 -07002144void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2145 const SkPaint* paint) {
2146 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2147
2148 SkRect storage;
2149 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00002150 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00002151 if (paint) {
2152 bounds = &paint->computeFastBounds(dst, &storage);
2153 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002154 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002155 return;
2156 }
2157 }
reed4c21dc52015-06-25 12:32:03 -07002158
2159 SkLazyPaint lazy;
2160 if (NULL == paint) {
2161 paint = lazy.init();
reed@google.com9987ec32011-09-07 11:57:52 +00002162 }
reed4c21dc52015-06-25 12:32:03 -07002163
2164 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2165
2166 while (iter.next()) {
2167 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
reed@google.com9987ec32011-09-07 11:57:52 +00002168 }
reed4c21dc52015-06-25 12:32:03 -07002169
2170 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002171}
2172
reed41af9662015-01-05 07:49:08 -08002173void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2174 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002175 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002176 SkDEBUGCODE(bitmap.validate();)
2177
reed4c21dc52015-06-25 12:32:03 -07002178 SkRect storage;
2179 const SkRect* bounds = &dst;
2180 if (NULL == paint || paint->canComputeFastBounds()) {
2181 if (paint) {
2182 bounds = &paint->computeFastBounds(dst, &storage);
2183 }
2184 if (this->quickReject(*bounds)) {
2185 return;
2186 }
2187 }
2188
2189 SkLazyPaint lazy;
2190 if (NULL == paint) {
2191 paint = lazy.init();
2192 }
2193
2194 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2195
2196 while (iter.next()) {
2197 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2198 }
2199
2200 LOOPER_END
reed@google.com9987ec32011-09-07 11:57:52 +00002201}
2202
reed@google.comf67e4cf2011-03-15 20:56:58 +00002203class SkDeviceFilteredPaint {
2204public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002205 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002206 uint32_t filteredFlags = device->filterTextFlags(paint);
2207 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002208 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002209 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002210 fPaint = newPaint;
2211 } else {
2212 fPaint = &paint;
2213 }
2214 }
2215
reed@google.comf67e4cf2011-03-15 20:56:58 +00002216 const SkPaint& paint() const { return *fPaint; }
2217
2218private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002219 const SkPaint* fPaint;
2220 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002221};
2222
bungeman@google.com52c748b2011-08-22 21:30:43 +00002223void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2224 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002225 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002226 draw.fDevice->drawRect(draw, r, paint);
2227 } else {
2228 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002229 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002230 draw.fDevice->drawRect(draw, r, p);
2231 }
2232}
2233
2234void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2235 const char text[], size_t byteLength,
2236 SkScalar x, SkScalar y) {
2237 SkASSERT(byteLength == 0 || text != NULL);
2238
2239 // nothing to draw
2240 if (text == NULL || byteLength == 0 ||
2241 draw.fClip->isEmpty() ||
2242 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2243 return;
2244 }
2245
2246 SkScalar width = 0;
2247 SkPoint start;
2248
2249 start.set(0, 0); // to avoid warning
2250 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2251 SkPaint::kStrikeThruText_Flag)) {
2252 width = paint.measureText(text, byteLength);
2253
2254 SkScalar offsetX = 0;
2255 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2256 offsetX = SkScalarHalf(width);
2257 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2258 offsetX = width;
2259 }
2260 start.set(x - offsetX, y);
2261 }
2262
2263 if (0 == width) {
2264 return;
2265 }
2266
2267 uint32_t flags = paint.getFlags();
2268
2269 if (flags & (SkPaint::kUnderlineText_Flag |
2270 SkPaint::kStrikeThruText_Flag)) {
2271 SkScalar textSize = paint.getTextSize();
2272 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2273 SkRect r;
2274
2275 r.fLeft = start.fX;
2276 r.fRight = start.fX + width;
2277
2278 if (flags & SkPaint::kUnderlineText_Flag) {
2279 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2280 start.fY);
2281 r.fTop = offset;
2282 r.fBottom = offset + height;
2283 DrawRect(draw, paint, r, textSize);
2284 }
2285 if (flags & SkPaint::kStrikeThruText_Flag) {
2286 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2287 start.fY);
2288 r.fTop = offset;
2289 r.fBottom = offset + height;
2290 DrawRect(draw, paint, r, textSize);
2291 }
2292 }
2293}
2294
reed@google.come0d9ce82014-04-23 04:00:17 +00002295void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2296 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002297 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002298
2299 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002300 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002301 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002302 DrawTextDecorations(iter, dfp.paint(),
2303 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002304 }
2305
reed@google.com4e2b3d32011-04-07 14:18:59 +00002306 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002307}
2308
reed@google.come0d9ce82014-04-23 04:00:17 +00002309void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2310 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002311 SkPoint textOffset = SkPoint::Make(0, 0);
2312
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002313 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002314
reed@android.com8a1c16f2008-12-17 15:59:43 +00002315 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002316 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002317 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002318 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002319 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002320
reed@google.com4e2b3d32011-04-07 14:18:59 +00002321 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002322}
2323
reed@google.come0d9ce82014-04-23 04:00:17 +00002324void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2325 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002326
2327 SkPoint textOffset = SkPoint::Make(0, constY);
2328
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002329 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002330
reed@android.com8a1c16f2008-12-17 15:59:43 +00002331 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002332 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002333 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002334 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002335 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002336
reed@google.com4e2b3d32011-04-07 14:18:59 +00002337 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002338}
2339
reed@google.come0d9ce82014-04-23 04:00:17 +00002340void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2341 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002342 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002343
reed@android.com8a1c16f2008-12-17 15:59:43 +00002344 while (iter.next()) {
2345 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002346 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002347 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002348
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002349 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002350}
2351
fmalita00d5c2c2014-08-21 08:53:26 -07002352void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2353 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002354
fmalita85d5eb92015-03-04 11:20:12 -08002355 SkRect storage;
2356 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002357 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002358 storage = blob->bounds().makeOffset(x, y);
2359 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002360
fmalita85d5eb92015-03-04 11:20:12 -08002361 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002362 return;
2363 }
2364 }
2365
fmalita024f9962015-03-03 19:08:17 -08002366 // We cannot filter in the looper as we normally do, because the paint is
2367 // incomplete at this point (text-related attributes are embedded within blob run paints).
2368 SkDrawFilter* drawFilter = fMCRec->fFilter;
2369 fMCRec->fFilter = NULL;
2370
fmalita85d5eb92015-03-04 11:20:12 -08002371 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002372
fmalitaaa1b9122014-08-28 14:32:24 -07002373 while (iter.next()) {
2374 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002375 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002376 }
2377
fmalitaaa1b9122014-08-28 14:32:24 -07002378 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002379
2380 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002381}
2382
reed@google.come0d9ce82014-04-23 04:00:17 +00002383// These will become non-virtual, so they always call the (virtual) onDraw... method
2384void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2385 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002386 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002387 this->onDrawText(text, byteLength, x, y, paint);
2388}
2389void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2390 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002391 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002392 this->onDrawPosText(text, byteLength, pos, paint);
2393}
2394void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2395 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002396 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002397 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2398}
2399void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2400 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002401 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002402 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2403}
fmalita00d5c2c2014-08-21 08:53:26 -07002404void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2405 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002406 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002407 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002408 this->onDrawTextBlob(blob, x, y, paint);
2409 }
2410}
reed@google.come0d9ce82014-04-23 04:00:17 +00002411
reed41af9662015-01-05 07:49:08 -08002412void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2413 const SkPoint verts[], const SkPoint texs[],
2414 const SkColor colors[], SkXfermode* xmode,
2415 const uint16_t indices[], int indexCount,
2416 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002417 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002418 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002419
reed@android.com8a1c16f2008-12-17 15:59:43 +00002420 while (iter.next()) {
2421 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002422 colors, xmode, indices, indexCount,
2423 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002424 }
reed@google.com4b226022011-01-11 18:32:13 +00002425
reed@google.com4e2b3d32011-04-07 14:18:59 +00002426 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002427}
2428
dandovb3c9d1c2014-08-12 08:34:29 -07002429void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2430 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002431 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002432 if (NULL == cubics) {
2433 return;
2434 }
mtklein6cfa73a2014-08-13 13:33:49 -07002435
dandovecfff212014-08-04 10:02:00 -07002436 // Since a patch is always within the convex hull of the control points, we discard it when its
2437 // bounding rectangle is completely outside the current clip.
2438 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002439 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002440 if (this->quickReject(bounds)) {
2441 return;
2442 }
mtklein6cfa73a2014-08-13 13:33:49 -07002443
dandovb3c9d1c2014-08-12 08:34:29 -07002444 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2445}
2446
2447void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2448 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2449
dandovecfff212014-08-04 10:02:00 -07002450 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002451
dandovecfff212014-08-04 10:02:00 -07002452 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002453 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002454 }
mtklein6cfa73a2014-08-13 13:33:49 -07002455
dandovecfff212014-08-04 10:02:00 -07002456 LOOPER_END
2457}
2458
reeda8db7282015-07-07 10:22:31 -07002459void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2460 if (dr) {
2461 if (x || y) {
2462 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2463 this->onDrawDrawable(dr, &matrix);
2464 } else {
2465 this->onDrawDrawable(dr, NULL);
2466 }
reed6a070dc2014-11-11 19:36:09 -08002467 }
2468}
2469
reeda8db7282015-07-07 10:22:31 -07002470void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2471 if (dr) {
2472 if (matrix && matrix->isIdentity()) {
2473 matrix = NULL;
2474 }
2475 this->onDrawDrawable(dr, matrix);
2476 }
2477}
2478
2479void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2480 SkRect bounds = dr->getBounds();
2481 if (matrix) {
2482 matrix->mapRect(&bounds);
2483 }
2484 if (this->quickReject(bounds)) {
2485 return;
2486 }
2487 dr->draw(this, matrix);
reed6a070dc2014-11-11 19:36:09 -08002488}
2489
reed71c3c762015-06-24 10:29:17 -07002490void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2491 const SkColor colors[], int count, SkXfermode::Mode mode,
2492 const SkRect* cull, const SkPaint* paint) {
2493 if (cull && this->quickReject(*cull)) {
2494 return;
2495 }
2496
2497 SkPaint pnt;
2498 if (paint) {
2499 pnt = *paint;
2500 }
2501
2502 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, NULL)
2503 while (iter.next()) {
2504 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2505 }
2506 LOOPER_END
2507}
2508
reed@android.com8a1c16f2008-12-17 15:59:43 +00002509//////////////////////////////////////////////////////////////////////////////
2510// These methods are NOT virtual, and therefore must call back into virtual
2511// methods, rather than actually drawing themselves.
2512//////////////////////////////////////////////////////////////////////////////
2513
2514void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002515 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002516 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002517 SkPaint paint;
2518
2519 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002520 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002521 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002522 }
2523 this->drawPaint(paint);
2524}
2525
reed@android.com845fdac2009-06-23 03:01:32 +00002526void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002527 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002528 SkPaint paint;
2529
2530 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002531 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002532 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002533 }
2534 this->drawPaint(paint);
2535}
2536
2537void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002538 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002539 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002540
reed@android.com8a1c16f2008-12-17 15:59:43 +00002541 pt.set(x, y);
2542 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2543}
2544
2545void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002546 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002547 SkPoint pt;
2548 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002549
reed@android.com8a1c16f2008-12-17 15:59:43 +00002550 pt.set(x, y);
2551 paint.setColor(color);
2552 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2553}
2554
2555void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2556 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002557 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002558 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002559
reed@android.com8a1c16f2008-12-17 15:59:43 +00002560 pts[0].set(x0, y0);
2561 pts[1].set(x1, y1);
2562 this->drawPoints(kLines_PointMode, 2, pts, paint);
2563}
2564
2565void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2566 SkScalar right, SkScalar bottom,
2567 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002568 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002569 SkRect r;
2570
2571 r.set(left, top, right, bottom);
2572 this->drawRect(r, paint);
2573}
2574
2575void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2576 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002577 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002578 if (radius < 0) {
2579 radius = 0;
2580 }
2581
2582 SkRect r;
2583 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002584 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002585}
2586
2587void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2588 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002589 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002590 if (rx > 0 && ry > 0) {
2591 if (paint.canComputeFastBounds()) {
2592 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002593 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002594 return;
2595 }
2596 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002597 SkRRect rrect;
2598 rrect.setRectXY(r, rx, ry);
2599 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002600 } else {
2601 this->drawRect(r, paint);
2602 }
2603}
2604
reed@android.com8a1c16f2008-12-17 15:59:43 +00002605void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2606 SkScalar sweepAngle, bool useCenter,
2607 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002608 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002609 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2610 this->drawOval(oval, paint);
2611 } else {
2612 SkPath path;
2613 if (useCenter) {
2614 path.moveTo(oval.centerX(), oval.centerY());
2615 }
2616 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2617 if (useCenter) {
2618 path.close();
2619 }
2620 this->drawPath(path, paint);
2621 }
2622}
2623
2624void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2625 const SkPath& path, SkScalar hOffset,
2626 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002627 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002628 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002629
reed@android.com8a1c16f2008-12-17 15:59:43 +00002630 matrix.setTranslate(hOffset, vOffset);
2631 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2632}
2633
reed@android.comf76bacf2009-05-13 14:00:33 +00002634///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002635
2636/**
2637 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2638 * against the playback cost of recursing into the subpicture to get at its actual ops.
2639 *
2640 * For now we pick a conservatively small value, though measurement (and other heuristics like
2641 * the type of ops contained) may justify changing this value.
2642 */
2643#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002644
reedd5fa1a42014-08-09 11:08:05 -07002645void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002646 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002647 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002648 if (matrix && matrix->isIdentity()) {
2649 matrix = NULL;
2650 }
reed1c2c4412015-04-30 13:09:24 -07002651 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2652 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2653 picture->playback(this);
2654 } else {
2655 this->onDrawPicture(picture, matrix, paint);
2656 }
reedd5fa1a42014-08-09 11:08:05 -07002657 }
2658}
robertphillips9b14f262014-06-04 05:40:44 -07002659
reedd5fa1a42014-08-09 11:08:05 -07002660void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2661 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002662 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002663 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002664 // Canvas has to first give the device the opportunity to render
2665 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002666 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002667 return; // the device has rendered the entire picture
2668 }
2669 }
2670
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002671 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002672 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002673}
2674
reed@android.com8a1c16f2008-12-17 15:59:43 +00002675///////////////////////////////////////////////////////////////////////////////
2676///////////////////////////////////////////////////////////////////////////////
2677
2678SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002679 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002680
2681 SkASSERT(canvas);
2682
2683 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2684 fDone = !fImpl->next();
2685}
2686
2687SkCanvas::LayerIter::~LayerIter() {
2688 fImpl->~SkDrawIter();
2689}
2690
2691void SkCanvas::LayerIter::next() {
2692 fDone = !fImpl->next();
2693}
2694
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002695SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002696 return fImpl->getDevice();
2697}
2698
2699const SkMatrix& SkCanvas::LayerIter::matrix() const {
2700 return fImpl->getMatrix();
2701}
2702
2703const SkPaint& SkCanvas::LayerIter::paint() const {
2704 const SkPaint* paint = fImpl->getPaint();
2705 if (NULL == paint) {
2706 paint = &fDefaultPaint;
2707 }
2708 return *paint;
2709}
2710
2711const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2712int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2713int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002714
2715///////////////////////////////////////////////////////////////////////////////
2716
fmalitac3b589a2014-06-05 12:40:07 -07002717SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002718
2719///////////////////////////////////////////////////////////////////////////////
2720
2721static bool supported_for_raster_canvas(const SkImageInfo& info) {
2722 switch (info.alphaType()) {
2723 case kPremul_SkAlphaType:
2724 case kOpaque_SkAlphaType:
2725 break;
2726 default:
2727 return false;
2728 }
2729
2730 switch (info.colorType()) {
2731 case kAlpha_8_SkColorType:
2732 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002733 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002734 break;
2735 default:
2736 return false;
2737 }
2738
2739 return true;
2740}
2741
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002742SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2743 if (!supported_for_raster_canvas(info)) {
2744 return NULL;
2745 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002746
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002747 SkBitmap bitmap;
2748 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2749 return NULL;
2750 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002751 return SkNEW_ARGS(SkCanvas, (bitmap));
2752}
reedd5fa1a42014-08-09 11:08:05 -07002753
2754///////////////////////////////////////////////////////////////////////////////
2755
2756SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002757 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002758 : fCanvas(canvas)
2759 , fSaveCount(canvas->getSaveCount())
2760{
bsalomon49f085d2014-09-05 13:34:00 -07002761 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002762 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002763 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002764 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002765 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002766 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002767 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002768 canvas->save();
2769 }
mtklein6cfa73a2014-08-13 13:33:49 -07002770
bsalomon49f085d2014-09-05 13:34:00 -07002771 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002772 canvas->concat(*matrix);
2773 }
2774}
2775
2776SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2777 fCanvas->restoreToCount(fSaveCount);
2778}