blob: 34d6aaa0ab4ddbb9ae5f158a846d77636c326642 [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"
senorblanco@chromium.org9c397442012-09-27 21:57:45 +000012#include "SkDeviceImageFilterProxy.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkDraw.h"
reed3cb38402015-02-06 08:36:15 -080014#include "SkDrawable.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkDrawFilter.h"
16#include "SkDrawLooper.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080017#include "SkErrorInternals.h"
piotaixrb5fae932014-09-24 13:03:30 -070018#include "SkImage.h"
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +000019#include "SkMetaData.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,
reed61f501f2015-04-29 08:34:00 -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;
273 fBitmap = &fDevice->accessBitmap(true);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274 fPaint = rec->fPaint;
reed@android.comf2b98d62010-12-20 18:26:13 +0000275 SkDEBUGCODE(this->validate();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276
277 fCurrLayer = rec->fNext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 // fCurrLayer may be NULL now
reed@android.com199f1082009-06-10 02:12:47 +0000279
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 return true;
281 }
282 return false;
283 }
reed@google.com4b226022011-01-11 18:32:13 +0000284
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000285 SkBaseDevice* getDevice() const { return fDevice; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000286 int getX() const { return fDevice->getOrigin().x(); }
287 int getY() const { return fDevice->getOrigin().y(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288 const SkMatrix& getMatrix() const { return *fMatrix; }
289 const SkRegion& getClip() const { return *fClip; }
290 const SkPaint* getPaint() const { return fPaint; }
reed@google.com6f8f2922011-03-04 22:27:10 +0000291
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292private:
293 SkCanvas* fCanvas;
294 const DeviceCM* fCurrLayer;
295 const SkPaint* fPaint; // May be null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 SkBool8 fSkipEmptyClips;
297
298 typedef SkDraw INHERITED;
299};
300
301/////////////////////////////////////////////////////////////////////////////
302
reeddbc3cef2015-04-29 12:18:57 -0700303static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
304 return lazy->isValid() ? lazy->get() : lazy->set(orig);
305}
306
307/**
308 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
309 * colorfilter, else return NULL.
310 */
311static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
reeddbc3cef2015-04-29 12:18:57 -0700312 SkImageFilter* imgf = paint.getImageFilter();
313 if (!imgf) {
314 return NULL;
315 }
316
317 SkColorFilter* imgCF;
318 if (!imgf->asAColorFilter(&imgCF)) {
319 return NULL;
320 }
321
322 SkColorFilter* paintCF = paint.getColorFilter();
323 if (NULL == paintCF) {
324 // there is no existing paint colorfilter, so we can just return the imagefilter's
325 return imgCF;
326 }
327
328 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
329 // and we need to combine them into a single colorfilter.
330 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
331 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
reeddbc3cef2015-04-29 12:18:57 -0700332}
333
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334class AutoDrawLooper {
335public:
reed4a8126e2014-09-22 07:29:03 -0700336 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000337 bool skipLayerForImageFilter = false,
338 const SkRect* bounds = NULL) : fOrigPaint(paint) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000339 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 fFilter = canvas->getDrawFilter();
reed4a8126e2014-09-22 07:29:03 -0700341 fPaint = &fOrigPaint;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000342 fSaveCount = canvas->getSaveCount();
reed5c476fb2015-04-20 08:04:21 -0700343 fTempLayerForImageFilter = false;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000344 fDone = false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345
reeddbc3cef2015-04-29 12:18:57 -0700346 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
347 if (simplifiedCF) {
348 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
349 paint->setColorFilter(simplifiedCF)->unref();
350 paint->setImageFilter(NULL);
351 fPaint = paint;
352 }
353
354 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
reed5c476fb2015-04-20 08:04:21 -0700355 /**
356 * We implement ImageFilters for a given draw by creating a layer, then applying the
357 * imagefilter to the pixels of that layer (its backing surface/image), and then
358 * we call restore() to xfer that layer to the main canvas.
359 *
360 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
361 * 2. Generate the src pixels:
362 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
363 * return (fPaint). We then draw the primitive (using srcover) into a cleared
364 * buffer/surface.
365 * 3. Restore the layer created in #1
366 * The imagefilter is passed the buffer/surface from the layer (now filled with the
367 * src pixels of the primitive). It returns a new "filtered" buffer, which we
368 * draw onto the previous layer using the xfermode from the original paint.
369 */
reed@google.com8926b162012-03-23 15:36:36 +0000370 SkPaint tmp;
reeddbc3cef2015-04-29 12:18:57 -0700371 tmp.setImageFilter(fPaint->getImageFilter());
372 tmp.setXfermode(fPaint->getXfermode());
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000373 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag,
reed76033be2015-03-14 10:54:31 -0700374 SkCanvas::kFullLayer_SaveLayerStrategy);
reed5c476fb2015-04-20 08:04:21 -0700375 fTempLayerForImageFilter = true;
376 // we remove the imagefilter/xfermode inside doNext()
reed@google.com8926b162012-03-23 15:36:36 +0000377 }
378
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000379 if (SkDrawLooper* looper = paint.getLooper()) {
380 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
381 looper->contextSize());
382 fLooperContext = looper->createContext(canvas, buffer);
reed@google.com129ec222012-05-15 13:24:09 +0000383 fIsSimple = false;
384 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000385 fLooperContext = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000386 // can we be marked as simple?
reed5c476fb2015-04-20 08:04:21 -0700387 fIsSimple = !fFilter && !fTempLayerForImageFilter;
reed@google.com4e2b3d32011-04-07 14:18:59 +0000388 }
piotaixrb5fae932014-09-24 13:03:30 -0700389
reed4a8126e2014-09-22 07:29:03 -0700390 uint32_t oldFlags = paint.getFlags();
391 fNewPaintFlags = filter_paint_flags(props, oldFlags);
392 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
reeddbc3cef2015-04-29 12:18:57 -0700393 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700394 paint->setFlags(fNewPaintFlags);
395 fPaint = paint;
396 // if we're not simple, doNext() will take care of calling setFlags()
397 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000398 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000399
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400 ~AutoDrawLooper() {
reed5c476fb2015-04-20 08:04:21 -0700401 if (fTempLayerForImageFilter) {
reed@google.com8926b162012-03-23 15:36:36 +0000402 fCanvas->internalRestore();
403 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000404 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000405 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000406
reed@google.com4e2b3d32011-04-07 14:18:59 +0000407 const SkPaint& paint() const {
408 SkASSERT(fPaint);
409 return *fPaint;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000410 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000411
reed@google.com129ec222012-05-15 13:24:09 +0000412 bool next(SkDrawFilter::Type drawType) {
413 if (fDone) {
414 return false;
415 } else if (fIsSimple) {
416 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000417 return !fPaint->nothingToDraw();
418 } else {
419 return this->doNext(drawType);
420 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000421 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000422
reed@android.com8a1c16f2008-12-17 15:59:43 +0000423private:
reeddbc3cef2015-04-29 12:18:57 -0700424 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
425 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000426 SkCanvas* fCanvas;
427 const SkPaint& fOrigPaint;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000428 SkDrawFilter* fFilter;
429 const SkPaint* fPaint;
430 int fSaveCount;
reed4a8126e2014-09-22 07:29:03 -0700431 uint32_t fNewPaintFlags;
reed5c476fb2015-04-20 08:04:21 -0700432 bool fTempLayerForImageFilter;
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +0000433 bool fDone;
reed@google.com129ec222012-05-15 13:24:09 +0000434 bool fIsSimple;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000435 SkDrawLooper::Context* fLooperContext;
436 SkSmallAllocator<1, 32> fLooperContextAllocator;
reed@google.com129ec222012-05-15 13:24:09 +0000437
438 bool doNext(SkDrawFilter::Type drawType);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000439};
440
reed@google.com129ec222012-05-15 13:24:09 +0000441bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
reed@google.com632e1a22011-10-06 12:37:00 +0000442 fPaint = NULL;
reed@google.com129ec222012-05-15 13:24:09 +0000443 SkASSERT(!fIsSimple);
reed5c476fb2015-04-20 08:04:21 -0700444 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
reed@google.com129ec222012-05-15 13:24:09 +0000445
reeddbc3cef2015-04-29 12:18:57 -0700446 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
447 *fLazyPaintInit.get() : fOrigPaint);
reed4a8126e2014-09-22 07:29:03 -0700448 paint->setFlags(fNewPaintFlags);
reed@google.com129ec222012-05-15 13:24:09 +0000449
reed5c476fb2015-04-20 08:04:21 -0700450 if (fTempLayerForImageFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000451 paint->setImageFilter(NULL);
reed5c476fb2015-04-20 08:04:21 -0700452 paint->setXfermode(NULL);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000453 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000454
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000455 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000456 fDone = true;
reed@google.com129ec222012-05-15 13:24:09 +0000457 return false;
458 }
459 if (fFilter) {
reed@google.com971aca72012-11-26 20:26:54 +0000460 if (!fFilter->filter(paint, drawType)) {
461 fDone = true;
462 return false;
463 }
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000464 if (NULL == fLooperContext) {
reed@google.com129ec222012-05-15 13:24:09 +0000465 // no looper means we only draw once
466 fDone = true;
467 }
468 }
469 fPaint = paint;
470
471 // if we only came in here for the imagefilter, mark us as done
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000472 if (!fLooperContext && !fFilter) {
reed@google.com129ec222012-05-15 13:24:09 +0000473 fDone = true;
reed@google.com632e1a22011-10-06 12:37:00 +0000474 }
475
476 // call this after any possible paint modifiers
477 if (fPaint->nothingToDraw()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000478 fPaint = NULL;
479 return false;
480 }
reed@google.com4e2b3d32011-04-07 14:18:59 +0000481 return true;
482}
483
reed@android.com8a1c16f2008-12-17 15:59:43 +0000484////////// macros to place around the internal draw calls //////////////////
485
reed@google.com8926b162012-03-23 15:36:36 +0000486#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
reed@google.com97af1a62012-08-28 12:19:02 +0000487 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700488 AutoDrawLooper looper(this, fProps, paint, true); \
reed@google.com8926b162012-03-23 15:36:36 +0000489 while (looper.next(type)) { \
reed@google.com8926b162012-03-23 15:36:36 +0000490 SkDrawIter iter(this);
491
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +0000492#define LOOPER_BEGIN(paint, type, bounds) \
reed@google.com97af1a62012-08-28 12:19:02 +0000493 this->predrawNotify(); \
reed4a8126e2014-09-22 07:29:03 -0700494 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
reed@google.com4e2b3d32011-04-07 14:18:59 +0000495 while (looper.next(type)) { \
reed@android.com8a1c16f2008-12-17 15:59:43 +0000496 SkDrawIter iter(this);
reed@google.com4b226022011-01-11 18:32:13 +0000497
reed@google.com4e2b3d32011-04-07 14:18:59 +0000498#define LOOPER_END }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000499
500////////////////////////////////////////////////////////////////////////////
501
mtkleinfeaadee2015-04-08 11:25:48 -0700502void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
503 this->restoreToCount(1);
504 fCachedLocalClipBounds.setEmpty();
505 fCachedLocalClipBoundsDirty = true;
506 fClipStack->reset();
507 fMCRec->reset(bounds);
508
509 // We're peering through a lot of structs here. Only at this scope do we
510 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
511 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
512}
513
reedd9544982014-09-09 18:46:22 -0700514SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
515 fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
reed@google.comc0784db2013-12-13 21:16:12 +0000516 fCachedLocalClipBounds.setEmpty();
517 fCachedLocalClipBoundsDirty = true;
caryclark@google.com8f0a7b82012-11-07 14:54:49 +0000518 fAllowSoftClip = true;
caryclark@google.com45a75fb2013-04-25 13:34:40 +0000519 fAllowSimplifyClip = false;
reedf92c8662014-08-18 08:02:43 -0700520 fDeviceCMDirty = true;
reed2ff1fce2014-12-11 07:07:37 -0800521 fSaveCount = 1;
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000522 fMetaData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523
reed687fa1c2015-04-07 08:00:56 -0700524 fClipStack.reset(SkNEW(SkClipStack));
525
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526 fMCRec = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700527 new (fMCRec) MCRec(fConservativeRasterClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528
reeda499f902015-05-01 09:34:31 -0700529 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
530 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
531 new (fDeviceCMStorage) DeviceCM(NULL, NULL, NULL, fConservativeRasterClip, false);
reedb679ca82015-04-07 04:40:48 -0700532
reed@android.com8a1c16f2008-12-17 15:59:43 +0000533 fMCRec->fTopLayer = fMCRec->fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534
reed@google.com97af1a62012-08-28 12:19:02 +0000535 fSurfaceBase = NULL;
reed@android.comf2b98d62010-12-20 18:26:13 +0000536
reedf92c8662014-08-18 08:02:43 -0700537 if (device) {
reedb2db8982014-11-13 12:41:02 -0800538 device->initForRootLayer(fProps.pixelGeometry());
reed4a8126e2014-09-22 07:29:03 -0700539 if (device->forceConservativeRasterClip()) {
540 fConservativeRasterClip = true;
541 }
reedf92c8662014-08-18 08:02:43 -0700542 device->onAttachToCanvas(this);
543 fMCRec->fLayer->fDevice = SkRef(device);
reed78e27682014-11-19 08:04:34 -0800544 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
reedf92c8662014-08-18 08:02:43 -0700545 }
546 return device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000547}
548
reed@google.comcde92112011-07-06 20:00:52 +0000549SkCanvas::SkCanvas()
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000550 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700551 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000552{
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000553 inc_canvas();
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000554
reedd9544982014-09-09 18:46:22 -0700555 this->init(NULL, kDefault_InitFlags);
vandebo@chromium.org8d84fac2010-10-13 22:13:05 +0000556}
557
reedd9544982014-09-09 18:46:22 -0700558static SkBitmap make_nopixels(int width, int height) {
559 SkBitmap bitmap;
560 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
561 return bitmap;
562}
563
564class SkNoPixelsBitmapDevice : public SkBitmapDevice {
565public:
reed78e27682014-11-19 08:04:34 -0800566 SkNoPixelsBitmapDevice(const SkIRect& bounds)
567 : INHERITED(make_nopixels(bounds.width(), bounds.height()))
568 {
569 this->setOrigin(bounds.x(), bounds.y());
570 }
reedd9544982014-09-09 18:46:22 -0700571
572private:
piotaixrb5fae932014-09-24 13:03:30 -0700573
reedd9544982014-09-09 18:46:22 -0700574 typedef SkBitmapDevice INHERITED;
575};
576
reed96a857e2015-01-25 10:33:58 -0800577SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000578 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed96a857e2015-01-25 10:33:58 -0800579 , fProps(SkSurfacePropsCopyOrDefault(props))
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000580{
581 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700582
reed78e27682014-11-19 08:04:34 -0800583 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
584 (SkIRect::MakeWH(width, height))), kDefault_InitFlags)->unref();
reedd9544982014-09-09 18:46:22 -0700585}
skia.committer@gmail.comba124482014-02-01 03:01:57 +0000586
reed78e27682014-11-19 08:04:34 -0800587SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700588 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700589 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
reedd9544982014-09-09 18:46:22 -0700590{
591 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700592
reed78e27682014-11-19 08:04:34 -0800593 this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds)), flags)->unref();
reedd9544982014-09-09 18:46:22 -0700594}
595
reed4a8126e2014-09-22 07:29:03 -0700596SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
reedd9544982014-09-09 18:46:22 -0700597 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700598 , fProps(SkSurfacePropsCopyOrDefault(props))
reedd9544982014-09-09 18:46:22 -0700599{
600 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700601
reedd9544982014-09-09 18:46:22 -0700602 this->init(device, flags);
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000603}
604
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000605SkCanvas::SkCanvas(SkBaseDevice* device)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000606 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700607 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000608{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000609 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700610
reedd9544982014-09-09 18:46:22 -0700611 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612}
613
reed4a8126e2014-09-22 07:29:03 -0700614SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
reed3716fd02014-09-21 09:39:55 -0700615 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
reed4a8126e2014-09-22 07:29:03 -0700616 , fProps(props)
reed3716fd02014-09-21 09:39:55 -0700617{
618 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700619
reed4a8126e2014-09-22 07:29:03 -0700620 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
621 this->init(device, kDefault_InitFlags);
622}
reed29c857d2014-09-21 10:25:07 -0700623
reed4a8126e2014-09-22 07:29:03 -0700624SkCanvas::SkCanvas(const SkBitmap& bitmap)
625 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
626 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
627{
628 inc_canvas();
piotaixrb5fae932014-09-24 13:03:30 -0700629
reed4a8126e2014-09-22 07:29:03 -0700630 SkAutoTUnref<SkBaseDevice> device(SkNEW_ARGS(SkBitmapDevice, (bitmap)));
631 this->init(device, kDefault_InitFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000632}
633
634SkCanvas::~SkCanvas() {
635 // free up the contents of our deque
636 this->restoreToCount(1); // restore everything but the last
reed@google.com7c202932011-12-14 18:48:05 +0000637
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638 this->internalRestore(); // restore the last, since we're going away
639
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000640 SkDELETE(fMetaData);
vandebo@chromium.orgb70ae312010-10-15 18:58:19 +0000641
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642 dec_canvas();
643}
644
reed@android.com8a1c16f2008-12-17 15:59:43 +0000645SkDrawFilter* SkCanvas::getDrawFilter() const {
646 return fMCRec->fFilter;
647}
648
649SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
reed51985e32015-04-11 08:04:56 -0700650 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000651 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
652 return filter;
653}
654
mike@reedtribe.org74bb77e2012-09-26 02:24:45 +0000655SkMetaData& SkCanvas::getMetaData() {
656 // metadata users are rare, so we lazily allocate it. If that changes we
657 // can decide to just make it a field in the device (rather than a ptr)
658 if (NULL == fMetaData) {
659 fMetaData = new SkMetaData;
660 }
661 return *fMetaData;
662}
663
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664///////////////////////////////////////////////////////////////////////////////
665
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000666void SkCanvas::flush() {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000667 SkBaseDevice* device = this->getDevice();
junov@chromium.orgbf6c1e42012-01-30 14:53:22 +0000668 if (device) {
669 device->flush();
670 }
671}
672
bsalomon@google.com4ebe3822014-02-26 20:22:32 +0000673SkISize SkCanvas::getTopLayerSize() const {
674 SkBaseDevice* d = this->getTopDevice();
675 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
676}
677
678SkIPoint SkCanvas::getTopLayerOrigin() const {
679 SkBaseDevice* d = this->getTopDevice();
680 return d ? d->getOrigin() : SkIPoint::Make(0, 0);
681}
682
683SkISize SkCanvas::getBaseLayerSize() const {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000684 SkBaseDevice* d = this->getDevice();
reed@google.com210ce002011-11-01 14:24:23 +0000685 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
686}
687
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000688SkBaseDevice* SkCanvas::getDevice() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000689 // return root device
robertphillips@google.comc0290622012-07-16 21:20:03 +0000690 MCRec* rec = (MCRec*) fMCStack.front();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691 SkASSERT(rec && rec->fLayer);
692 return rec->fLayer->fDevice;
693}
694
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000695SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
reed@google.com0b53d592012-03-19 18:26:34 +0000696 if (updateMatrixClip) {
697 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
698 }
reed@google.com9266fed2011-03-30 00:18:03 +0000699 return fMCRec->fTopLayer->fDevice;
700}
701
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000702bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
703 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
704 return false;
705 }
706
707 bool weAllocated = false;
708 if (NULL == bitmap->pixelRef()) {
reed84825042014-09-02 12:50:45 -0700709 if (!bitmap->tryAllocPixels()) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000710 return false;
711 }
712 weAllocated = true;
713 }
714
715 SkBitmap bm(*bitmap);
716 bm.lockPixels();
717 if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
718 return true;
719 }
720
721 if (weAllocated) {
722 bitmap->setPixelRef(NULL);
723 }
724 return false;
725}
reed@google.com51df9e32010-12-23 19:29:18 +0000726
bsalomon@google.comc6980972011-11-02 19:57:21 +0000727bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000728 SkIRect r = srcRect;
729 const SkISize size = this->getBaseLayerSize();
730 if (!r.intersect(0, 0, size.width(), size.height())) {
731 bitmap->reset();
732 return false;
733 }
734
reed84825042014-09-02 12:50:45 -0700735 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000736 // bitmap will already be reset.
737 return false;
738 }
739 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
740 bitmap->reset();
741 return false;
742 }
743 return true;
744}
745
reed96472de2014-12-10 09:53:42 -0800746bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000747 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000748 if (!device) {
749 return false;
750 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000751 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800752
reed96472de2014-12-10 09:53:42 -0800753 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
754 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000755 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000756 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000757
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000758 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800759 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000760}
761
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000762bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
763 if (bitmap.getTexture()) {
764 return false;
765 }
766 SkBitmap bm(bitmap);
767 bm.lockPixels();
768 if (bm.getPixels()) {
769 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
770 }
771 return false;
772}
773
774bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
775 int x, int y) {
776 switch (origInfo.colorType()) {
777 case kUnknown_SkColorType:
778 case kIndex_8_SkColorType:
779 return false;
780 default:
781 break;
782 }
783 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
784 return false;
785 }
786
787 const SkISize size = this->getBaseLayerSize();
788 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
789 if (!target.intersect(0, 0, size.width(), size.height())) {
790 return false;
791 }
792
793 SkBaseDevice* device = this->getDevice();
794 if (!device) {
795 return false;
796 }
797
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000798 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700799 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000800
801 // if x or y are negative, then we have to adjust pixels
802 if (x > 0) {
803 x = 0;
804 }
805 if (y > 0) {
806 y = 0;
807 }
808 // here x,y are either 0 or negative
809 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
810
reed4af35f32014-06-27 17:47:49 -0700811 // Tell our owning surface to bump its generation ID
812 this->predrawNotify();
813
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000814 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000815 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000816}
reed@google.com51df9e32010-12-23 19:29:18 +0000817
junov@google.com4370aed2012-01-18 16:21:08 +0000818SkCanvas* SkCanvas::canvasForDrawIter() {
819 return this;
820}
821
reed@android.com8a1c16f2008-12-17 15:59:43 +0000822//////////////////////////////////////////////////////////////////////////////
823
reed@android.com8a1c16f2008-12-17 15:59:43 +0000824void SkCanvas::updateDeviceCMCache() {
825 if (fDeviceCMDirty) {
826 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700827 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000829
reed@android.com8a1c16f2008-12-17 15:59:43 +0000830 if (NULL == layer->fNext) { // only one layer
reed687fa1c2015-04-07 08:00:56 -0700831 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000832 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000833 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000834 do {
reed687fa1c2015-04-07 08:00:56 -0700835 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836 } while ((layer = layer->fNext) != NULL);
837 }
838 fDeviceCMDirty = false;
839 }
840}
841
reed@android.com8a1c16f2008-12-17 15:59:43 +0000842///////////////////////////////////////////////////////////////////////////////
843
reed2ff1fce2014-12-11 07:07:37 -0800844void SkCanvas::checkForDeferredSave() {
845 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800846 this->doSave();
847 }
848}
849
reedf0090cb2014-11-26 08:55:51 -0800850int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800851#ifdef SK_DEBUG
852 int count = 0;
853 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
854 for (;;) {
855 const MCRec* rec = (const MCRec*)iter.next();
856 if (!rec) {
857 break;
858 }
859 count += 1 + rec->fDeferredSaveCount;
860 }
861 SkASSERT(count == fSaveCount);
862#endif
863 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800864}
865
866int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800867 fSaveCount += 1;
868 fMCRec->fDeferredSaveCount += 1;
869 return this->getSaveCount() - 1; // return our prev value
870}
871
872void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800873 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700874
875 SkASSERT(fMCRec->fDeferredSaveCount > 0);
876 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800877 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800878}
879
880void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800881 if (fMCRec->fDeferredSaveCount > 0) {
882 SkASSERT(fSaveCount > 1);
883 fSaveCount -= 1;
884 fMCRec->fDeferredSaveCount -= 1;
885 } else {
886 // check for underflow
887 if (fMCStack.count() > 1) {
888 this->willRestore();
889 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700890 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800891 this->internalRestore();
892 this->didRestore();
893 }
reedf0090cb2014-11-26 08:55:51 -0800894 }
895}
896
897void SkCanvas::restoreToCount(int count) {
898 // sanity check
899 if (count < 1) {
900 count = 1;
901 }
mtkleinf0f14112014-12-12 08:46:25 -0800902
reedf0090cb2014-11-26 08:55:51 -0800903 int n = this->getSaveCount() - count;
904 for (int i = 0; i < n; ++i) {
905 this->restore();
906 }
907}
908
reed2ff1fce2014-12-11 07:07:37 -0800909void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000910 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700911 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000912 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000913
reed687fa1c2015-04-07 08:00:56 -0700914 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000915}
916
reed@android.com8a1c16f2008-12-17 15:59:43 +0000917static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000918#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000919 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000920#else
921 return true;
922#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000923}
924
junov@chromium.orga907ac32012-02-24 21:54:07 +0000925bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700926 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000927 SkIRect clipBounds;
928 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000929 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000930 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000931
reed96e657d2015-03-10 17:30:07 -0700932 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
933
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000934 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700935 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000936 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000937 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700938 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000939 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000940
reed96e657d2015-03-10 17:30:07 -0700941 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000942 r.roundOut(&ir);
943 // early exit if the layer's bounds are clipped out
944 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000945 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700946 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700947 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000948 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000949 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000950 }
951 } else { // no user bounds, so just use the clip
952 ir = clipBounds;
953 }
reed180aec42015-03-11 10:39:04 -0700954 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000956 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -0700957 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -0700958 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -0700959 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -0700960 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000961 }
962
963 if (intersection) {
964 *intersection = ir;
965 }
966 return true;
967}
968
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000969int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800970 if (gIgnoreSaveLayerBounds) {
971 bounds = NULL;
972 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000973 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -0700974 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700975 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800976 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000977}
978
reed2ff1fce2014-12-11 07:07:37 -0800979int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800980 if (gIgnoreSaveLayerBounds) {
981 bounds = NULL;
982 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000983 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -0700984 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700985 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800986 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000987}
988
reed2ff1fce2014-12-11 07:07:37 -0800989void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -0700990 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000991#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000992 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000993#endif
994
junov@chromium.orga907ac32012-02-24 21:54:07 +0000995 // do this before we create the layer. We don't call the public save() since
996 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -0800997 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000998
999 fDeviceCMDirty = true;
1000
1001 SkIRect ir;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +00001002 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -08001003 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001004 }
1005
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001006 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1007 // the clipRectBounds() call above?
1008 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001009 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001010 }
1011
reed76033be2015-03-14 10:54:31 -07001012 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001013 SkPixelGeometry geo = fProps.pixelGeometry();
1014 if (paint) {
reed76033be2015-03-14 10:54:31 -07001015 // TODO: perhaps add a query to filters so we might preserve opaqueness...
1016 if (paint->getImageFilter() || paint->getColorFilter()) {
1017 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001018 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001019 }
1020 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001021 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1022 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023
reedb2db8982014-11-13 12:41:02 -08001024 SkBaseDevice* device = this->getTopDevice();
1025 if (NULL == device) {
1026 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001027 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001028 }
reedb2db8982014-11-13 12:41:02 -08001029
reed61f501f2015-04-29 08:34:00 -07001030 bool forceSpriteOnRestore = false;
1031 {
1032 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
1033 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo);
1034 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
1035 if (NULL == newDev) {
1036 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
1037 newDev = SkBitmapDevice::Create(createInfo.fInfo);
1038 if (NULL == newDev) {
1039 SkErrorInternals::SetError(kInternalError_SkError,
1040 "Unable to create device for layer.");
1041 return;
1042 }
1043 forceSpriteOnRestore = true;
1044 }
1045 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001046 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001047
reed@google.com6f8f2922011-03-04 22:27:10 +00001048 device->setOrigin(ir.fLeft, ir.fTop);
reed61f501f2015-04-29 08:34:00 -07001049 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip,
1050 forceSpriteOnRestore));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001051 device->unref();
1052
1053 layer->fNext = fMCRec->fTopLayer;
1054 fMCRec->fLayer = layer;
1055 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056}
1057
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001058int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1059 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1060}
1061
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1063 SaveFlags flags) {
1064 if (0xFF == alpha) {
1065 return this->saveLayer(bounds, NULL, flags);
1066 } else {
1067 SkPaint tmpPaint;
1068 tmpPaint.setAlpha(alpha);
1069 return this->saveLayer(bounds, &tmpPaint, flags);
1070 }
1071}
1072
reed@android.com8a1c16f2008-12-17 15:59:43 +00001073void SkCanvas::internalRestore() {
1074 SkASSERT(fMCStack.count() != 0);
1075
1076 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001077 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001078
reed687fa1c2015-04-07 08:00:56 -07001079 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001080
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001081 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001082 DeviceCM* layer = fMCRec->fLayer; // may be null
1083 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1084 fMCRec->fLayer = NULL;
1085
1086 // now do the normal restore()
1087 fMCRec->~MCRec(); // balanced in save()
1088 fMCStack.pop_back();
1089 fMCRec = (MCRec*)fMCStack.back();
1090
1091 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1092 since if we're being recorded, we don't want to record this (the
1093 recorder will have already recorded the restore).
1094 */
bsalomon49f085d2014-09-05 13:34:00 -07001095 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001096 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001097 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001098 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001099 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001100 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001101 fDeviceCMDirty = true;
reedb679ca82015-04-07 04:40:48 -07001102 SkDELETE(layer);
1103 } else {
1104 // we're at the root
reeda499f902015-05-01 09:34:31 -07001105 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001106 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001107 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001108 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001109}
1110
reed4a8126e2014-09-22 07:29:03 -07001111SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1112 if (NULL == props) {
1113 props = &fProps;
1114 }
1115 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001116}
1117
reed4a8126e2014-09-22 07:29:03 -07001118SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001119 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001120 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001121}
1122
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001123SkImageInfo SkCanvas::imageInfo() const {
1124 SkBaseDevice* dev = this->getDevice();
1125 if (dev) {
1126 return dev->imageInfo();
1127 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001128 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001129 }
1130}
1131
1132const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1133 return this->onPeekPixels(info, rowBytes);
1134}
1135
1136const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1137 SkBaseDevice* dev = this->getDevice();
1138 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1139}
1140
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001141void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1142 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1143 if (pixels && origin) {
1144 *origin = this->getTopDevice(false)->getOrigin();
1145 }
1146 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001147}
1148
1149void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1150 SkBaseDevice* dev = this->getTopDevice();
1151 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1152}
1153
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001154SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1155 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1156 if (NULL == fAddr) {
1157 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001158 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001159 return; // failure, fAddr is NULL
1160 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001161 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1162 return; // failure, fAddr is NULL
1163 }
1164 fAddr = fBitmap.getPixels();
1165 fRowBytes = fBitmap.rowBytes();
1166 }
1167 SkASSERT(fAddr); // success
1168}
1169
1170bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1171 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001172 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001173 } else {
1174 bitmap->reset();
1175 return false;
1176 }
1177}
1178
reed@android.com8a1c16f2008-12-17 15:59:43 +00001179/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001180void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001181 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001182 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001183 return;
1184 }
1185
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001186 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001187 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001188 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001189 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001190
1191 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001192
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001193 SkRect storage;
1194 const SkRect* bounds = NULL;
1195 if (paint && paint->canComputeFastBounds()) {
1196 bitmap.getBounds(&storage);
1197 matrix.mapRect(&storage);
1198 bounds = &paint->computeFastBounds(storage, &storage);
1199 }
1200
1201 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001202
1203 while (iter.next()) {
1204 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1205 }
1206
1207 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001208}
1209
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001210void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001211 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001212 SkPaint tmp;
1213 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001214 paint = &tmp;
1215 }
reed@google.com4b226022011-01-11 18:32:13 +00001216
reed@google.com8926b162012-03-23 15:36:36 +00001217 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001218 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001219 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001220 paint = &looper.paint();
1221 SkImageFilter* filter = paint->getImageFilter();
1222 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001223 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001224 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001225 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001226 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001227 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001228 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001229 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001230 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001231 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001232 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001233 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001234 SkPaint tmpUnfiltered(*paint);
1235 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001236 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1237 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001238 }
reed61f501f2015-04-29 08:34:00 -07001239 } else if (deviceIsBitmapDevice) {
1240 const SkBitmap& src = srcDev->accessBitmap(false);
1241 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001242 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001243 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001244 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001245 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001246 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001247}
1248
reed41af9662015-01-05 07:49:08 -08001249void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001250 if (gTreatSpriteAsBitmap) {
1251 this->save();
1252 this->resetMatrix();
1253 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1254 this->restore();
1255 return;
1256 }
1257
danakj9881d632014-11-26 12:41:06 -08001258 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001259 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001260 return;
1261 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001262 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001263
reed@google.com8926b162012-03-23 15:36:36 +00001264 SkPaint tmp;
1265 if (NULL == paint) {
1266 paint = &tmp;
1267 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001268
reed@google.com8926b162012-03-23 15:36:36 +00001269 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001270
reed@google.com8926b162012-03-23 15:36:36 +00001271 while (iter.next()) {
1272 paint = &looper.paint();
1273 SkImageFilter* filter = paint->getImageFilter();
1274 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1275 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001276 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001277 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001278 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001279 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001280 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001281 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001282 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001283 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001284 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001285 SkPaint tmpUnfiltered(*paint);
1286 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001287 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001288 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001289 }
1290 } else {
1291 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1292 }
1293 }
1294 LOOPER_END
1295}
1296
reed@android.com8a1c16f2008-12-17 15:59:43 +00001297/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001298void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001299 SkMatrix m;
1300 m.setTranslate(dx, dy);
1301 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001302}
1303
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001304void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001305 SkMatrix m;
1306 m.setScale(sx, sy);
1307 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001308}
1309
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001310void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001311 SkMatrix m;
1312 m.setRotate(degrees);
1313 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001314}
1315
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001316void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001317 SkMatrix m;
1318 m.setSkew(sx, sy);
1319 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001320}
1321
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001322void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001323 if (matrix.isIdentity()) {
1324 return;
1325 }
1326
reed2ff1fce2014-12-11 07:07:37 -08001327 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001328 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001329 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001330 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001331
1332 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001333}
1334
reed@android.com8a1c16f2008-12-17 15:59:43 +00001335void SkCanvas::setMatrix(const SkMatrix& matrix) {
reed2ff1fce2014-12-11 07:07:37 -08001336 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001338 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001339 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001340 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001341}
1342
reed@android.com8a1c16f2008-12-17 15:59:43 +00001343void SkCanvas::resetMatrix() {
1344 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001345
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346 matrix.reset();
1347 this->setMatrix(matrix);
1348}
1349
1350//////////////////////////////////////////////////////////////////////////////
1351
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001352void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001353 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001354 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1355 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001356}
1357
1358void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001359#ifdef SK_ENABLE_CLIP_QUICKREJECT
1360 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001361 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001362 return false;
1363 }
1364
reed@google.com3b3e8952012-08-16 20:53:31 +00001365 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001366 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001367 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001368
reed687fa1c2015-04-07 08:00:56 -07001369 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001370 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001371 }
1372 }
1373#endif
1374
reed@google.com5c3d1472011-02-22 19:12:23 +00001375 AutoValidateClip avc(this);
1376
reed@android.com8a1c16f2008-12-17 15:59:43 +00001377 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001378 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001379 if (!fAllowSoftClip) {
1380 edgeStyle = kHard_ClipEdgeStyle;
1381 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001382
reed1f836ee2014-07-07 07:49:34 -07001383 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001384 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001385 // the matrix. This means we don't have to a) make a path, and b) tell
1386 // the region code to scan-convert the path, only to discover that it
1387 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001388 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001389
reed1f836ee2014-07-07 07:49:34 -07001390 fMCRec->fMatrix.mapRect(&r, rect);
reed687fa1c2015-04-07 08:00:56 -07001391 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001392 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001393 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001394 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001395 // and clip against that, since it can handle any matrix. However, to
1396 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1397 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001398 SkPath path;
1399
1400 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001401 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001402 }
1403}
1404
reed73e714e2014-09-04 09:02:23 -07001405static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1406 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001407 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001408}
1409
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001410void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001411 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001412 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001413 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001414 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1415 } else {
1416 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001417 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001418}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001419
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001420void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001421 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001422 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001423 AutoValidateClip avc(this);
1424
1425 fDeviceCMDirty = true;
1426 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001427 if (!fAllowSoftClip) {
1428 edgeStyle = kHard_ClipEdgeStyle;
1429 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001430
reed687fa1c2015-04-07 08:00:56 -07001431 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001432
1433 SkPath devPath;
1434 devPath.addRRect(transformedRRect);
1435
reed73e714e2014-09-04 09:02:23 -07001436 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001437 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001438 }
1439
1440 SkPath path;
1441 path.addRRect(rrect);
1442 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001443 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001444}
1445
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001446void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001447 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001448 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1449 SkRect r;
1450 if (!path.isInverseFillType() && path.isRect(&r)) {
1451 this->onClipRect(r, op, edgeStyle);
1452 } else {
1453 this->onClipPath(path, op, edgeStyle);
1454 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001455}
1456
1457void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001458#ifdef SK_ENABLE_CLIP_QUICKREJECT
1459 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001460 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001461 return false;
1462 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001463
reed@google.com3b3e8952012-08-16 20:53:31 +00001464 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001465 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001466 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001467
reed687fa1c2015-04-07 08:00:56 -07001468 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001469 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001470 }
1471 }
1472#endif
1473
reed@google.com5c3d1472011-02-22 19:12:23 +00001474 AutoValidateClip avc(this);
1475
reed@android.com8a1c16f2008-12-17 15:59:43 +00001476 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001477 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001478 if (!fAllowSoftClip) {
1479 edgeStyle = kHard_ClipEdgeStyle;
1480 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001481
1482 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001483 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001484
reed@google.comfe701122011-11-08 19:41:23 +00001485 // Check if the transfomation, or the original path itself
1486 // made us empty. Note this can also happen if we contained NaN
1487 // values. computing the bounds detects this, and will set our
1488 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1489 if (devPath.getBounds().isEmpty()) {
1490 // resetting the path will remove any NaN or other wanky values
1491 // that might upset our scan converter.
1492 devPath.reset();
1493 }
1494
reed@google.com5c3d1472011-02-22 19:12:23 +00001495 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001496 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001497
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001498 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001499 bool clipIsAA = getClipStack()->asPath(&devPath);
1500 if (clipIsAA) {
1501 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001502 }
fmalita1a481fe2015-02-04 07:39:34 -08001503
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001504 op = SkRegion::kReplace_Op;
1505 }
1506
reed73e714e2014-09-04 09:02:23 -07001507 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001508}
1509
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001510void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001511 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001512 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001513}
1514
1515void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001516 AutoValidateClip avc(this);
1517
reed@android.com8a1c16f2008-12-17 15:59:43 +00001518 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001519 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001520
reed@google.com5c3d1472011-02-22 19:12:23 +00001521 // todo: signal fClipStack that we have a region, and therefore (I guess)
1522 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001523 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001524
reed1f836ee2014-07-07 07:49:34 -07001525 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001526}
1527
reed@google.com819c9212011-02-23 18:56:55 +00001528#ifdef SK_DEBUG
1529void SkCanvas::validateClip() const {
1530 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001531 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001532 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001533 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001534 return;
1535 }
1536
reed@google.com819c9212011-02-23 18:56:55 +00001537 SkIRect ir;
1538 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001539 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001540
reed687fa1c2015-04-07 08:00:56 -07001541 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001542 const SkClipStack::Element* element;
1543 while ((element = iter.next()) != NULL) {
1544 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001545 case SkClipStack::Element::kRect_Type:
1546 element->getRect().round(&ir);
1547 tmpClip.op(ir, element->getOp());
1548 break;
1549 case SkClipStack::Element::kEmpty_Type:
1550 tmpClip.setEmpty();
1551 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001552 default: {
1553 SkPath path;
1554 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001555 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001556 break;
1557 }
reed@google.com819c9212011-02-23 18:56:55 +00001558 }
1559 }
reed@google.com819c9212011-02-23 18:56:55 +00001560}
1561#endif
1562
reed@google.com90c07ea2012-04-13 13:50:27 +00001563void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001564 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001565 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001566
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001567 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001568 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001569 }
1570}
1571
reed@google.com5c3d1472011-02-22 19:12:23 +00001572///////////////////////////////////////////////////////////////////////////////
1573
reed@google.com754de5f2014-02-24 19:38:20 +00001574bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001575 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001576}
1577
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001578bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001579 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001580}
1581
reed@google.com3b3e8952012-08-16 20:53:31 +00001582bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001583 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001584 return true;
1585
reed1f836ee2014-07-07 07:49:34 -07001586 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001587 return true;
1588 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001589
reed1f836ee2014-07-07 07:49:34 -07001590 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001591 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001592 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001593 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001594 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001595 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001596
reed@android.coma380ae42009-07-21 01:17:02 +00001597 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001598 // TODO: should we use | instead, or compare all 4 at once?
1599 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001600 return true;
1601 }
reed@google.comc0784db2013-12-13 21:16:12 +00001602 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001603 return true;
1604 }
1605 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001606 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001607}
1608
reed@google.com3b3e8952012-08-16 20:53:31 +00001609bool SkCanvas::quickReject(const SkPath& path) const {
1610 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001611}
1612
reed@google.com3b3e8952012-08-16 20:53:31 +00001613bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001614 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001615 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001616 return false;
1617 }
1618
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001619 SkMatrix inverse;
1620 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001621 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001622 if (bounds) {
1623 bounds->setEmpty();
1624 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001625 return false;
1626 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001627
bsalomon49f085d2014-09-05 13:34:00 -07001628 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001629 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001630 // adjust it outwards in case we are antialiasing
1631 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001632
reed@google.com8f4d2302013-12-17 16:44:46 +00001633 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1634 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001635 inverse.mapRect(bounds, r);
1636 }
1637 return true;
1638}
1639
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001640bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001641 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001642 if (clip.isEmpty()) {
1643 if (bounds) {
1644 bounds->setEmpty();
1645 }
1646 return false;
1647 }
1648
bsalomon49f085d2014-09-05 13:34:00 -07001649 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001650 *bounds = clip.getBounds();
1651 }
1652 return true;
1653}
1654
reed@android.com8a1c16f2008-12-17 15:59:43 +00001655const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001656 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001657}
1658
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001659const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001660 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001661}
1662
reed@google.com9c135db2014-03-12 18:28:35 +00001663GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1664 SkBaseDevice* dev = this->getTopDevice();
1665 return dev ? dev->accessRenderTarget() : NULL;
1666}
1667
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001668GrContext* SkCanvas::getGrContext() {
1669#if SK_SUPPORT_GPU
1670 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001671 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001672 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001673 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001674 return renderTarget->getContext();
1675 }
1676 }
1677#endif
1678
1679 return NULL;
1680
1681}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001682
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001683void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1684 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001685 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001686 if (outer.isEmpty()) {
1687 return;
1688 }
1689 if (inner.isEmpty()) {
1690 this->drawRRect(outer, paint);
1691 return;
1692 }
1693
1694 // We don't have this method (yet), but technically this is what we should
1695 // be able to assert...
1696 // SkASSERT(outer.contains(inner));
1697 //
1698 // For now at least check for containment of bounds
1699 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1700
1701 this->onDrawDRRect(outer, inner, paint);
1702}
1703
reed41af9662015-01-05 07:49:08 -08001704// These need to stop being virtual -- clients need to override the onDraw... versions
1705
1706void SkCanvas::drawPaint(const SkPaint& paint) {
1707 this->onDrawPaint(paint);
1708}
1709
1710void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1711 this->onDrawRect(r, paint);
1712}
1713
1714void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1715 this->onDrawOval(r, paint);
1716}
1717
1718void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1719 this->onDrawRRect(rrect, paint);
1720}
1721
1722void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1723 this->onDrawPoints(mode, count, pts, paint);
1724}
1725
1726void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1727 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1728 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1729 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1730 indices, indexCount, paint);
1731}
1732
1733void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1734 this->onDrawPath(path, paint);
1735}
1736
reeda85d4d02015-05-06 12:56:48 -07001737void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1738 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001739}
1740
1741void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1742 const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07001743 if (dst.isEmpty()) {
1744 return;
1745 }
reed41af9662015-01-05 07:49:08 -08001746 this->onDrawImageRect(image, src, dst, paint);
1747}
1748
1749void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001750 if (bitmap.empty()) {
1751 return;
1752 }
reed41af9662015-01-05 07:49:08 -08001753 this->onDrawBitmap(bitmap, dx, dy, paint);
1754}
1755
1756void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1757 const SkPaint* paint, DrawBitmapRectFlags flags) {
tomhudson2df6fd62015-04-09 09:20:19 -07001758 if (bitmap.empty()) {
1759 return;
1760 }
reed41af9662015-01-05 07:49:08 -08001761 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1762}
1763
1764void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1765 const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001766 if (bitmap.empty()) {
1767 return;
1768 }
reed41af9662015-01-05 07:49:08 -08001769 this->onDrawBitmapNine(bitmap, center, dst, paint);
1770}
1771
1772void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001773 if (bitmap.empty()) {
1774 return;
1775 }
reed41af9662015-01-05 07:49:08 -08001776 this->onDrawSprite(bitmap, left, top, paint);
1777}
1778
reed@android.com8a1c16f2008-12-17 15:59:43 +00001779//////////////////////////////////////////////////////////////////////////////
1780// These are the virtual drawing methods
1781//////////////////////////////////////////////////////////////////////////////
1782
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001783void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001784 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001785 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1786 }
1787}
1788
reed41af9662015-01-05 07:49:08 -08001789void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001790 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001791 this->internalDrawPaint(paint);
1792}
1793
1794void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001795 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001796
1797 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001798 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001799 }
1800
reed@google.com4e2b3d32011-04-07 14:18:59 +00001801 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001802}
1803
reed41af9662015-01-05 07:49:08 -08001804void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1805 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001806 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001807 if ((long)count <= 0) {
1808 return;
1809 }
1810
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001811 SkRect r, storage;
1812 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001813 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001814 // special-case 2 points (common for drawing a single line)
1815 if (2 == count) {
1816 r.set(pts[0], pts[1]);
1817 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001818 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001819 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001820 bounds = &paint.computeFastStrokeBounds(r, &storage);
1821 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001822 return;
1823 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001824 }
reed@google.coma584aed2012-05-16 14:06:02 +00001825
reed@android.com8a1c16f2008-12-17 15:59:43 +00001826 SkASSERT(pts != NULL);
1827
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001828 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001829
reed@android.com8a1c16f2008-12-17 15:59:43 +00001830 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001831 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001832 }
reed@google.com4b226022011-01-11 18:32:13 +00001833
reed@google.com4e2b3d32011-04-07 14:18:59 +00001834 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001835}
1836
reed41af9662015-01-05 07:49:08 -08001837void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001838 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001839 SkRect storage;
1840 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001841 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001842 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1843 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1844 SkRect tmp(r);
1845 tmp.sort();
1846
1847 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001848 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001849 return;
1850 }
1851 }
reed@google.com4b226022011-01-11 18:32:13 +00001852
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001853 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001854
1855 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001856 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001857 }
1858
reed@google.com4e2b3d32011-04-07 14:18:59 +00001859 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001860}
1861
reed41af9662015-01-05 07:49:08 -08001862void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001863 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001864 SkRect storage;
1865 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001866 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001867 bounds = &paint.computeFastBounds(oval, &storage);
1868 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001869 return;
1870 }
1871 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001872
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001873 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001874
1875 while (iter.next()) {
1876 iter.fDevice->drawOval(iter, oval, looper.paint());
1877 }
1878
1879 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001880}
1881
reed41af9662015-01-05 07:49:08 -08001882void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001883 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001884 SkRect storage;
1885 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001886 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001887 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1888 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001889 return;
1890 }
1891 }
1892
1893 if (rrect.isRect()) {
1894 // call the non-virtual version
1895 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001896 return;
1897 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001898 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001899 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1900 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001901 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001902
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001903 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001904
1905 while (iter.next()) {
1906 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1907 }
1908
1909 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001910}
1911
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001912void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1913 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001914 SkRect storage;
1915 const SkRect* bounds = NULL;
1916 if (paint.canComputeFastBounds()) {
1917 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1918 if (this->quickReject(*bounds)) {
1919 return;
1920 }
1921 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001922
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001923 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001924
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001925 while (iter.next()) {
1926 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1927 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001928
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001929 LOOPER_END
1930}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001931
reed41af9662015-01-05 07:49:08 -08001932void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001933 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001934 if (!path.isFinite()) {
1935 return;
1936 }
1937
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001938 SkRect storage;
1939 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001940 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001941 const SkRect& pathBounds = path.getBounds();
1942 bounds = &paint.computeFastBounds(pathBounds, &storage);
1943 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001944 return;
1945 }
1946 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001947
1948 const SkRect& r = path.getBounds();
1949 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001950 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001951 this->internalDrawPaint(paint);
1952 }
1953 return;
1954 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001955
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001956 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001957
1958 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001959 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001960 }
1961
reed@google.com4e2b3d32011-04-07 14:18:59 +00001962 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001963}
1964
reeda85d4d02015-05-06 12:56:48 -07001965void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001966 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07001967 SkRect bounds = SkRect::MakeXYWH(x, y,
1968 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
1969 if (NULL == paint || paint->canComputeFastBounds()) {
1970 if (paint) {
1971 paint->computeFastBounds(bounds, &bounds);
1972 }
1973 if (this->quickReject(bounds)) {
1974 return;
1975 }
1976 }
1977
1978 SkLazyPaint lazy;
1979 if (NULL == paint) {
1980 paint = lazy.init();
1981 }
1982
1983 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds)
1984
1985 while (iter.next()) {
1986 iter.fDevice->drawImage(iter, image, x, y, looper.paint());
1987 }
1988
1989 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07001990}
1991
reed41af9662015-01-05 07:49:08 -08001992void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1993 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001994 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
reeda85d4d02015-05-06 12:56:48 -07001995 SkRect storage;
1996 const SkRect* bounds = &dst;
1997 if (NULL == paint || paint->canComputeFastBounds()) {
1998 if (paint) {
1999 bounds = &paint->computeFastBounds(dst, &storage);
2000 }
2001 if (this->quickReject(*bounds)) {
2002 return;
2003 }
2004 }
2005 SkLazyPaint lazy;
2006 if (NULL == paint) {
2007 paint = lazy.init();
2008 }
2009
2010 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2011
2012 while (iter.next()) {
2013 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint());
2014 }
2015
2016 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002017}
2018
reed41af9662015-01-05 07:49:08 -08002019void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002020 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002021 SkDEBUGCODE(bitmap.validate();)
2022
reed@google.com3d608122011-11-21 15:16:16 +00002023 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002024 SkRect bounds = {
2025 x, y,
2026 x + SkIntToScalar(bitmap.width()),
2027 y + SkIntToScalar(bitmap.height())
2028 };
2029 if (paint) {
2030 (void)paint->computeFastBounds(bounds, &bounds);
2031 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002032 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002033 return;
2034 }
2035 }
reed@google.com4b226022011-01-11 18:32:13 +00002036
reed@android.com8a1c16f2008-12-17 15:59:43 +00002037 SkMatrix matrix;
2038 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00002039 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002040}
2041
reed@google.com9987ec32011-09-07 11:57:52 +00002042// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002043void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002044 const SkRect& dst, const SkPaint* paint,
2045 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002046 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002047 return;
2048 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002049
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002050 SkRect storage;
2051 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00002052 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002053 if (paint) {
2054 bounds = &paint->computeFastBounds(dst, &storage);
2055 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002056 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002057 return;
2058 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002059 }
reed@google.com3d608122011-11-21 15:16:16 +00002060
reed@google.com33535f32012-09-25 15:37:50 +00002061 SkLazyPaint lazy;
2062 if (NULL == paint) {
2063 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002064 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002065
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002066 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002067
reed@google.com33535f32012-09-25 15:37:50 +00002068 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002069 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00002070 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002071
reed@google.com33535f32012-09-25 15:37:50 +00002072 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002073}
2074
reed41af9662015-01-05 07:49:08 -08002075void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2076 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08002077 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002078 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002079 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00002080}
2081
reed@google.com9987ec32011-09-07 11:57:52 +00002082void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
2083 const SkIRect& center, const SkRect& dst,
2084 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002085 if (bitmap.drawsNothing()) {
2086 return;
2087 }
reed@google.com3d608122011-11-21 15:16:16 +00002088 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00002089 SkRect storage;
2090 const SkRect* bounds = &dst;
2091 if (paint) {
2092 bounds = &paint->computeFastBounds(dst, &storage);
2093 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002094 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002095 return;
2096 }
2097 }
2098
reed@google.com9987ec32011-09-07 11:57:52 +00002099 const int32_t w = bitmap.width();
2100 const int32_t h = bitmap.height();
2101
2102 SkIRect c = center;
2103 // pin center to the bounds of the bitmap
2104 c.fLeft = SkMax32(0, center.fLeft);
2105 c.fTop = SkMax32(0, center.fTop);
2106 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2107 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2108
reed@google.com71121732012-09-18 15:14:33 +00002109 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002110 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00002111 };
2112 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002113 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00002114 };
reed@google.com9987ec32011-09-07 11:57:52 +00002115 SkScalar dstX[4] = {
2116 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2117 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2118 };
2119 SkScalar dstY[4] = {
2120 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2121 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2122 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002123
reed@google.com9987ec32011-09-07 11:57:52 +00002124 if (dstX[1] > dstX[2]) {
2125 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2126 dstX[2] = dstX[1];
2127 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002128
reed@google.com9987ec32011-09-07 11:57:52 +00002129 if (dstY[1] > dstY[2]) {
2130 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2131 dstY[2] = dstY[1];
2132 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002133
reed@google.com9987ec32011-09-07 11:57:52 +00002134 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00002135 SkRect s, d;
2136
reed@google.com9987ec32011-09-07 11:57:52 +00002137 s.fTop = srcY[y];
2138 s.fBottom = srcY[y+1];
2139 d.fTop = dstY[y];
2140 d.fBottom = dstY[y+1];
2141 for (int x = 0; x < 3; x++) {
2142 s.fLeft = srcX[x];
2143 s.fRight = srcX[x+1];
2144 d.fLeft = dstX[x];
2145 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002146 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00002147 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00002148 }
2149 }
2150}
2151
reed41af9662015-01-05 07:49:08 -08002152void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2153 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002154 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002155 SkDEBUGCODE(bitmap.validate();)
2156
2157 // Need a device entry-point, so gpu can use a mesh
2158 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2159}
2160
reed@google.comf67e4cf2011-03-15 20:56:58 +00002161class SkDeviceFilteredPaint {
2162public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002163 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002164 uint32_t filteredFlags = device->filterTextFlags(paint);
2165 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002166 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002167 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002168 fPaint = newPaint;
2169 } else {
2170 fPaint = &paint;
2171 }
2172 }
2173
reed@google.comf67e4cf2011-03-15 20:56:58 +00002174 const SkPaint& paint() const { return *fPaint; }
2175
2176private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002177 const SkPaint* fPaint;
2178 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002179};
2180
bungeman@google.com52c748b2011-08-22 21:30:43 +00002181void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2182 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002183 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002184 draw.fDevice->drawRect(draw, r, paint);
2185 } else {
2186 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002187 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002188 draw.fDevice->drawRect(draw, r, p);
2189 }
2190}
2191
2192void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2193 const char text[], size_t byteLength,
2194 SkScalar x, SkScalar y) {
2195 SkASSERT(byteLength == 0 || text != NULL);
2196
2197 // nothing to draw
2198 if (text == NULL || byteLength == 0 ||
2199 draw.fClip->isEmpty() ||
2200 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2201 return;
2202 }
2203
2204 SkScalar width = 0;
2205 SkPoint start;
2206
2207 start.set(0, 0); // to avoid warning
2208 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2209 SkPaint::kStrikeThruText_Flag)) {
2210 width = paint.measureText(text, byteLength);
2211
2212 SkScalar offsetX = 0;
2213 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2214 offsetX = SkScalarHalf(width);
2215 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2216 offsetX = width;
2217 }
2218 start.set(x - offsetX, y);
2219 }
2220
2221 if (0 == width) {
2222 return;
2223 }
2224
2225 uint32_t flags = paint.getFlags();
2226
2227 if (flags & (SkPaint::kUnderlineText_Flag |
2228 SkPaint::kStrikeThruText_Flag)) {
2229 SkScalar textSize = paint.getTextSize();
2230 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2231 SkRect r;
2232
2233 r.fLeft = start.fX;
2234 r.fRight = start.fX + width;
2235
2236 if (flags & SkPaint::kUnderlineText_Flag) {
2237 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2238 start.fY);
2239 r.fTop = offset;
2240 r.fBottom = offset + height;
2241 DrawRect(draw, paint, r, textSize);
2242 }
2243 if (flags & SkPaint::kStrikeThruText_Flag) {
2244 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2245 start.fY);
2246 r.fTop = offset;
2247 r.fBottom = offset + height;
2248 DrawRect(draw, paint, r, textSize);
2249 }
2250 }
2251}
2252
reed@google.come0d9ce82014-04-23 04:00:17 +00002253void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2254 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002255 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002256
2257 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002258 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002259 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002260 DrawTextDecorations(iter, dfp.paint(),
2261 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002262 }
2263
reed@google.com4e2b3d32011-04-07 14:18:59 +00002264 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002265}
2266
reed@google.come0d9ce82014-04-23 04:00:17 +00002267void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2268 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002269 SkPoint textOffset = SkPoint::Make(0, 0);
2270
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002271 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002272
reed@android.com8a1c16f2008-12-17 15:59:43 +00002273 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002274 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002275 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002276 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002277 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002278
reed@google.com4e2b3d32011-04-07 14:18:59 +00002279 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002280}
2281
reed@google.come0d9ce82014-04-23 04:00:17 +00002282void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2283 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002284
2285 SkPoint textOffset = SkPoint::Make(0, constY);
2286
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002287 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002288
reed@android.com8a1c16f2008-12-17 15:59:43 +00002289 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002290 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002291 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002292 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002293 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002294
reed@google.com4e2b3d32011-04-07 14:18:59 +00002295 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002296}
2297
reed@google.come0d9ce82014-04-23 04:00:17 +00002298void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2299 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002300 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002301
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302 while (iter.next()) {
2303 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002304 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002306
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002307 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002308}
2309
fmalita00d5c2c2014-08-21 08:53:26 -07002310void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2311 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002312
fmalita85d5eb92015-03-04 11:20:12 -08002313 SkRect storage;
2314 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002315 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002316 storage = blob->bounds().makeOffset(x, y);
2317 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002318
fmalita85d5eb92015-03-04 11:20:12 -08002319 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002320 return;
2321 }
2322 }
2323
fmalita024f9962015-03-03 19:08:17 -08002324 // We cannot filter in the looper as we normally do, because the paint is
2325 // incomplete at this point (text-related attributes are embedded within blob run paints).
2326 SkDrawFilter* drawFilter = fMCRec->fFilter;
2327 fMCRec->fFilter = NULL;
2328
fmalita85d5eb92015-03-04 11:20:12 -08002329 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002330
fmalitaaa1b9122014-08-28 14:32:24 -07002331 while (iter.next()) {
2332 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002333 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002334 }
2335
fmalitaaa1b9122014-08-28 14:32:24 -07002336 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002337
2338 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002339}
2340
reed@google.come0d9ce82014-04-23 04:00:17 +00002341// These will become non-virtual, so they always call the (virtual) onDraw... method
2342void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2343 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002344 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002345 this->onDrawText(text, byteLength, x, y, paint);
2346}
2347void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2348 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002349 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002350 this->onDrawPosText(text, byteLength, pos, paint);
2351}
2352void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2353 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002354 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002355 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2356}
2357void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2358 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002359 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002360 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2361}
fmalita00d5c2c2014-08-21 08:53:26 -07002362void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2363 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002364 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002365 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002366 this->onDrawTextBlob(blob, x, y, paint);
2367 }
2368}
reed@google.come0d9ce82014-04-23 04:00:17 +00002369
reed41af9662015-01-05 07:49:08 -08002370void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2371 const SkPoint verts[], const SkPoint texs[],
2372 const SkColor colors[], SkXfermode* xmode,
2373 const uint16_t indices[], int indexCount,
2374 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002375 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002376 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002377
reed@android.com8a1c16f2008-12-17 15:59:43 +00002378 while (iter.next()) {
2379 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002380 colors, xmode, indices, indexCount,
2381 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002382 }
reed@google.com4b226022011-01-11 18:32:13 +00002383
reed@google.com4e2b3d32011-04-07 14:18:59 +00002384 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002385}
2386
dandovb3c9d1c2014-08-12 08:34:29 -07002387void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2388 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002389 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002390 if (NULL == cubics) {
2391 return;
2392 }
mtklein6cfa73a2014-08-13 13:33:49 -07002393
dandovecfff212014-08-04 10:02:00 -07002394 // Since a patch is always within the convex hull of the control points, we discard it when its
2395 // bounding rectangle is completely outside the current clip.
2396 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002397 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002398 if (this->quickReject(bounds)) {
2399 return;
2400 }
mtklein6cfa73a2014-08-13 13:33:49 -07002401
dandovb3c9d1c2014-08-12 08:34:29 -07002402 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2403}
2404
2405void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2406 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2407
dandovecfff212014-08-04 10:02:00 -07002408 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002409
dandovecfff212014-08-04 10:02:00 -07002410 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002411 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002412 }
mtklein6cfa73a2014-08-13 13:33:49 -07002413
dandovecfff212014-08-04 10:02:00 -07002414 LOOPER_END
2415}
2416
reed3cb38402015-02-06 08:36:15 -08002417void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002418 if (dr && !this->quickReject(dr->getBounds())) {
2419 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002420 }
2421}
2422
reed3cb38402015-02-06 08:36:15 -08002423void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002424 dr->draw(this);
2425}
2426
reed@android.com8a1c16f2008-12-17 15:59:43 +00002427//////////////////////////////////////////////////////////////////////////////
2428// These methods are NOT virtual, and therefore must call back into virtual
2429// methods, rather than actually drawing themselves.
2430//////////////////////////////////////////////////////////////////////////////
2431
2432void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002433 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002434 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002435 SkPaint paint;
2436
2437 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002438 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002439 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002440 }
2441 this->drawPaint(paint);
2442}
2443
reed@android.com845fdac2009-06-23 03:01:32 +00002444void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002445 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002446 SkPaint paint;
2447
2448 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002449 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002450 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002451 }
2452 this->drawPaint(paint);
2453}
2454
2455void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002456 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002457 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002458
reed@android.com8a1c16f2008-12-17 15:59:43 +00002459 pt.set(x, y);
2460 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2461}
2462
2463void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002464 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002465 SkPoint pt;
2466 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002467
reed@android.com8a1c16f2008-12-17 15:59:43 +00002468 pt.set(x, y);
2469 paint.setColor(color);
2470 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2471}
2472
2473void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2474 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002475 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002476 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002477
reed@android.com8a1c16f2008-12-17 15:59:43 +00002478 pts[0].set(x0, y0);
2479 pts[1].set(x1, y1);
2480 this->drawPoints(kLines_PointMode, 2, pts, paint);
2481}
2482
2483void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2484 SkScalar right, SkScalar bottom,
2485 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002486 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002487 SkRect r;
2488
2489 r.set(left, top, right, bottom);
2490 this->drawRect(r, paint);
2491}
2492
2493void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2494 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002495 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002496 if (radius < 0) {
2497 radius = 0;
2498 }
2499
2500 SkRect r;
2501 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002502 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002503}
2504
2505void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2506 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002507 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002508 if (rx > 0 && ry > 0) {
2509 if (paint.canComputeFastBounds()) {
2510 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002511 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002512 return;
2513 }
2514 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002515 SkRRect rrect;
2516 rrect.setRectXY(r, rx, ry);
2517 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002518 } else {
2519 this->drawRect(r, paint);
2520 }
2521}
2522
reed@android.com8a1c16f2008-12-17 15:59:43 +00002523void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2524 SkScalar sweepAngle, bool useCenter,
2525 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002526 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002527 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2528 this->drawOval(oval, paint);
2529 } else {
2530 SkPath path;
2531 if (useCenter) {
2532 path.moveTo(oval.centerX(), oval.centerY());
2533 }
2534 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2535 if (useCenter) {
2536 path.close();
2537 }
2538 this->drawPath(path, paint);
2539 }
2540}
2541
2542void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2543 const SkPath& path, SkScalar hOffset,
2544 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002545 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002546 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002547
reed@android.com8a1c16f2008-12-17 15:59:43 +00002548 matrix.setTranslate(hOffset, vOffset);
2549 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2550}
2551
reed@android.comf76bacf2009-05-13 14:00:33 +00002552///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002553
2554/**
2555 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2556 * against the playback cost of recursing into the subpicture to get at its actual ops.
2557 *
2558 * For now we pick a conservatively small value, though measurement (and other heuristics like
2559 * the type of ops contained) may justify changing this value.
2560 */
2561#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002562
reedd5fa1a42014-08-09 11:08:05 -07002563void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002564 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002565 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002566 if (matrix && matrix->isIdentity()) {
2567 matrix = NULL;
2568 }
reed1c2c4412015-04-30 13:09:24 -07002569 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2570 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2571 picture->playback(this);
2572 } else {
2573 this->onDrawPicture(picture, matrix, paint);
2574 }
reedd5fa1a42014-08-09 11:08:05 -07002575 }
2576}
robertphillips9b14f262014-06-04 05:40:44 -07002577
reedd5fa1a42014-08-09 11:08:05 -07002578void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2579 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002580 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002581 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002582 // Canvas has to first give the device the opportunity to render
2583 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002584 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002585 return; // the device has rendered the entire picture
2586 }
2587 }
2588
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002589 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002590 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002591}
2592
reed@android.com8a1c16f2008-12-17 15:59:43 +00002593///////////////////////////////////////////////////////////////////////////////
2594///////////////////////////////////////////////////////////////////////////////
2595
2596SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002597 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002598
2599 SkASSERT(canvas);
2600
2601 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2602 fDone = !fImpl->next();
2603}
2604
2605SkCanvas::LayerIter::~LayerIter() {
2606 fImpl->~SkDrawIter();
2607}
2608
2609void SkCanvas::LayerIter::next() {
2610 fDone = !fImpl->next();
2611}
2612
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002613SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002614 return fImpl->getDevice();
2615}
2616
2617const SkMatrix& SkCanvas::LayerIter::matrix() const {
2618 return fImpl->getMatrix();
2619}
2620
2621const SkPaint& SkCanvas::LayerIter::paint() const {
2622 const SkPaint* paint = fImpl->getPaint();
2623 if (NULL == paint) {
2624 paint = &fDefaultPaint;
2625 }
2626 return *paint;
2627}
2628
2629const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2630int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2631int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002632
2633///////////////////////////////////////////////////////////////////////////////
2634
fmalitac3b589a2014-06-05 12:40:07 -07002635SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002636
2637///////////////////////////////////////////////////////////////////////////////
2638
2639static bool supported_for_raster_canvas(const SkImageInfo& info) {
2640 switch (info.alphaType()) {
2641 case kPremul_SkAlphaType:
2642 case kOpaque_SkAlphaType:
2643 break;
2644 default:
2645 return false;
2646 }
2647
2648 switch (info.colorType()) {
2649 case kAlpha_8_SkColorType:
2650 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002651 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002652 break;
2653 default:
2654 return false;
2655 }
2656
2657 return true;
2658}
2659
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002660SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2661 if (!supported_for_raster_canvas(info)) {
2662 return NULL;
2663 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002664
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002665 SkBitmap bitmap;
2666 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2667 return NULL;
2668 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002669 return SkNEW_ARGS(SkCanvas, (bitmap));
2670}
reedd5fa1a42014-08-09 11:08:05 -07002671
2672///////////////////////////////////////////////////////////////////////////////
2673
2674SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002675 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002676 : fCanvas(canvas)
2677 , fSaveCount(canvas->getSaveCount())
2678{
bsalomon49f085d2014-09-05 13:34:00 -07002679 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002680 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002681 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002682 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002683 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002684 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002685 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002686 canvas->save();
2687 }
mtklein6cfa73a2014-08-13 13:33:49 -07002688
bsalomon49f085d2014-09-05 13:34:00 -07002689 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002690 canvas->concat(*matrix);
2691 }
2692}
2693
2694SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2695 fCanvas->restoreToCount(fSaveCount);
2696}