blob: aa25ca0b41c96dcafe053d05d7066a50e8bcb8b8 [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,
reed86a17e72015-05-14 12:25:22 -0700121 bool conservativeRasterClip, bool deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700122 : fNext(NULL)
123 , fClip(conservativeRasterClip)
reed61f501f2015-04-29 08:34:00 -0700124 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
reedd9544982014-09-09 18:46:22 -0700125 {
126 if (NULL != device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 device->ref();
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000128 device->onAttachToCanvas(canvas);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 }
reed@google.com4b226022011-01-11 18:32:13 +0000130 fDevice = device;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000132 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000134 ~DeviceCM() {
bsalomon49f085d2014-09-05 13:34:00 -0700135 if (fDevice) {
robertphillips@google.com40a1ae42012-07-13 15:36:15 +0000136 fDevice->onDetachFromCanvas();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137 fDevice->unref();
138 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +0000139 SkDELETE(fPaint);
140 }
reed@google.com4b226022011-01-11 18:32:13 +0000141
mtkleinfeaadee2015-04-08 11:25:48 -0700142 void reset(const SkIRect& bounds) {
143 SkASSERT(!fPaint);
144 SkASSERT(!fNext);
145 SkASSERT(fDevice);
146 fClip.setRect(bounds);
147 }
148
reed@google.com045e62d2011-10-24 12:19:46 +0000149 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
150 const SkClipStack& clipStack, SkRasterClip* updateClip) {
reed@google.com6f8f2922011-03-04 22:27:10 +0000151 int x = fDevice->getOrigin().x();
152 int y = fDevice->getOrigin().y();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 int width = fDevice->width();
154 int height = fDevice->height();
reed@google.com4b226022011-01-11 18:32:13 +0000155
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156 if ((x | y) == 0) {
157 fMatrix = &totalMatrix;
158 fClip = totalClip;
159 } else {
160 fMatrixStorage = totalMatrix;
161 fMatrixStorage.postTranslate(SkIntToScalar(-x),
162 SkIntToScalar(-y));
163 fMatrix = &fMatrixStorage;
reed@google.com4b226022011-01-11 18:32:13 +0000164
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 totalClip.translate(-x, -y, &fClip);
166 }
167
reed@google.com045e62d2011-10-24 12:19:46 +0000168 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169
170 // intersect clip, but don't translate it (yet)
reed@google.com4b226022011-01-11 18:32:13 +0000171
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 if (updateClip) {
reed@google.com045e62d2011-10-24 12:19:46 +0000173 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174 SkRegion::kDifference_Op);
175 }
reed@google.com4b226022011-01-11 18:32:13 +0000176
robertphillips@google.com3fffb2e2012-10-09 22:30:18 +0000177 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
178
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179#ifdef SK_DEBUG
180 if (!fClip.isEmpty()) {
181 SkIRect deviceR;
182 deviceR.set(0, 0, width, height);
183 SkASSERT(deviceR.contains(fClip.getBounds()));
184 }
185#endif
reed@android.comf2b98d62010-12-20 18:26:13 +0000186 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187};
188
189/* This is the record we keep for each save/restore level in the stack.
190 Since a level optionally copies the matrix and/or stack, we have pointers
191 for these fields. If the value is copied for this level, the copy is
192 stored in the ...Storage field, and the pointer points to that. If the
193 value is not copied for this level, we ignore ...Storage, and just point
194 at the corresponding value in the previous level in the stack.
195*/
196class SkCanvas::MCRec {
197public:
reed1f836ee2014-07-07 07:49:34 -0700198 SkDrawFilter* fFilter; // the current filter (or null)
reedd9544982014-09-09 18:46:22 -0700199 DeviceCM* fLayer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 /* If there are any layers in the stack, this points to the top-most
201 one that is at or below this level in the stack (so we know what
202 bitmap/device to draw into from this level. This value is NOT
203 reference counted, since the real owner is either our fLayer field,
204 or a previous one in a lower level.)
205 */
reed2ff1fce2014-12-11 07:07:37 -0800206 DeviceCM* fTopLayer;
207 SkRasterClip fRasterClip;
208 SkMatrix fMatrix;
209 int fDeferredSaveCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210
reedd9544982014-09-09 18:46:22 -0700211 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
reedd9544982014-09-09 18:46:22 -0700212 fFilter = NULL;
213 fLayer = NULL;
214 fTopLayer = NULL;
reed2ff1fce2014-12-11 07:07:37 -0800215 fMatrix.reset();
216 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700217
reedd9544982014-09-09 18:46:22 -0700218 // don't bother initializing fNext
219 inc_rec();
220 }
reed2ff1fce2014-12-11 07:07:37 -0800221 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
reedd9544982014-09-09 18:46:22 -0700222 fFilter = SkSafeRef(prev.fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 fLayer = NULL;
reedd9544982014-09-09 18:46:22 -0700224 fTopLayer = prev.fTopLayer;
reed2ff1fce2014-12-11 07:07:37 -0800225 fDeferredSaveCount = 0;
piotaixrb5fae932014-09-24 13:03:30 -0700226
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 // don't bother initializing fNext
228 inc_rec();
229 }
230 ~MCRec() {
reed@google.com82065d62011-02-07 15:30:46 +0000231 SkSafeUnref(fFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 SkDELETE(fLayer);
233 dec_rec();
234 }
mtkleinfeaadee2015-04-08 11:25:48 -0700235
236 void reset(const SkIRect& bounds) {
237 SkASSERT(fLayer);
238 SkASSERT(fDeferredSaveCount == 0);
239
240 fMatrix.reset();
241 fRasterClip.setRect(bounds);
242 fLayer->reset(bounds);
243 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244};
245
246class SkDrawIter : public SkDraw {
247public:
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000248 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
junov@google.com4370aed2012-01-18 16:21:08 +0000249 canvas = canvas->canvasForDrawIter();
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000250 fCanvas = canvas;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 canvas->updateDeviceCMCache();
252
reed687fa1c2015-04-07 08:00:56 -0700253 fClipStack = canvas->fClipStack;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 fCurrLayer = canvas->fMCRec->fTopLayer;
tomhudson@google.com8a0b0292011-09-13 14:41:06 +0000255 fSkipEmptyClips = skipEmptyClips;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256 }
reed@google.com4b226022011-01-11 18:32:13 +0000257
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258 bool next() {
259 // skip over recs with empty clips
260 if (fSkipEmptyClips) {
261 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
262 fCurrLayer = fCurrLayer->fNext;
263 }
264 }
265
reed@google.comf68c5e22012-02-24 16:38:58 +0000266 const DeviceCM* rec = fCurrLayer;
267 if (rec && rec->fDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268
269 fMatrix = rec->fMatrix;
reed@google.com045e62d2011-10-24 12:19:46 +0000270 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
271 fRC = &rec->fClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 fDevice = rec->fDevice;
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;
reed86a17e72015-05-14 12:25:22 -0700531 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
reedcf01e312015-05-23 19:14:51 -0700715 SkAutoPixmapUnlock unlocker;
716 if (bitmap->requestLock(&unlocker)) {
717 const SkPixmap& pm = unlocker.pixmap();
718 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
719 return true;
720 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000721 }
722
723 if (weAllocated) {
724 bitmap->setPixelRef(NULL);
725 }
726 return false;
727}
reed@google.com51df9e32010-12-23 19:29:18 +0000728
bsalomon@google.comc6980972011-11-02 19:57:21 +0000729bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000730 SkIRect r = srcRect;
731 const SkISize size = this->getBaseLayerSize();
732 if (!r.intersect(0, 0, size.width(), size.height())) {
733 bitmap->reset();
734 return false;
735 }
736
reed84825042014-09-02 12:50:45 -0700737 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000738 // bitmap will already be reset.
739 return false;
740 }
741 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
742 bitmap->reset();
743 return false;
744 }
745 return true;
746}
747
reed96472de2014-12-10 09:53:42 -0800748bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +0000749 SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +0000750 if (!device) {
751 return false;
752 }
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000753 const SkISize size = this->getBaseLayerSize();
mtkleinf0f14112014-12-12 08:46:25 -0800754
reed96472de2014-12-10 09:53:42 -0800755 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
756 if (!rec.trim(size.width(), size.height())) {
bsalomon@google.comdaba14b2011-11-02 20:10:48 +0000757 return false;
bsalomon@google.comc6980972011-11-02 19:57:21 +0000758 }
skia.committer@gmail.comdb0c8752014-03-18 03:02:11 +0000759
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000760 // The device can assert that the requested area is always contained in its bounds
reed96472de2014-12-10 09:53:42 -0800761 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
reed@google.com51df9e32010-12-23 19:29:18 +0000762}
763
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000764bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
765 if (bitmap.getTexture()) {
766 return false;
767 }
reedcf01e312015-05-23 19:14:51 -0700768
769 SkAutoPixmapUnlock unlocker;
770 if (bitmap.requestLock(&unlocker)) {
771 const SkPixmap& pm = unlocker.pixmap();
772 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000773 }
774 return false;
775}
776
777bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
778 int x, int y) {
779 switch (origInfo.colorType()) {
780 case kUnknown_SkColorType:
781 case kIndex_8_SkColorType:
782 return false;
783 default:
784 break;
785 }
786 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
787 return false;
788 }
789
790 const SkISize size = this->getBaseLayerSize();
791 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
792 if (!target.intersect(0, 0, size.width(), size.height())) {
793 return false;
794 }
795
796 SkBaseDevice* device = this->getDevice();
797 if (!device) {
798 return false;
799 }
800
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000801 // the intersect may have shrunk info's logical size
reede5ea5002014-09-03 11:54:58 -0700802 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000803
804 // if x or y are negative, then we have to adjust pixels
805 if (x > 0) {
806 x = 0;
807 }
808 if (y > 0) {
809 y = 0;
810 }
811 // here x,y are either 0 or negative
812 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
813
reed4af35f32014-06-27 17:47:49 -0700814 // Tell our owning surface to bump its generation ID
815 this->predrawNotify();
816
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000817 // The device can assert that the requested area is always contained in its bounds
commit-bot@chromium.org4ef54f82014-03-17 17:03:18 +0000818 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000819}
reed@google.com51df9e32010-12-23 19:29:18 +0000820
junov@google.com4370aed2012-01-18 16:21:08 +0000821SkCanvas* SkCanvas::canvasForDrawIter() {
822 return this;
823}
824
reed@android.com8a1c16f2008-12-17 15:59:43 +0000825//////////////////////////////////////////////////////////////////////////////
826
reed@android.com8a1c16f2008-12-17 15:59:43 +0000827void SkCanvas::updateDeviceCMCache() {
828 if (fDeviceCMDirty) {
829 const SkMatrix& totalMatrix = this->getTotalMatrix();
reed1f836ee2014-07-07 07:49:34 -0700830 const SkRasterClip& totalClip = fMCRec->fRasterClip;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000831 DeviceCM* layer = fMCRec->fTopLayer;
reed@google.com4b226022011-01-11 18:32:13 +0000832
reed@android.com8a1c16f2008-12-17 15:59:43 +0000833 if (NULL == layer->fNext) { // only one layer
reed687fa1c2015-04-07 08:00:56 -0700834 layer->updateMC(totalMatrix, totalClip, *fClipStack, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000835 } else {
reed@google.com045e62d2011-10-24 12:19:46 +0000836 SkRasterClip clip(totalClip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000837 do {
reed687fa1c2015-04-07 08:00:56 -0700838 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000839 } while ((layer = layer->fNext) != NULL);
840 }
841 fDeviceCMDirty = false;
842 }
843}
844
reed@android.com8a1c16f2008-12-17 15:59:43 +0000845///////////////////////////////////////////////////////////////////////////////
846
reed2ff1fce2014-12-11 07:07:37 -0800847void SkCanvas::checkForDeferredSave() {
848 if (fMCRec->fDeferredSaveCount > 0) {
reed2ff1fce2014-12-11 07:07:37 -0800849 this->doSave();
850 }
851}
852
reedf0090cb2014-11-26 08:55:51 -0800853int SkCanvas::getSaveCount() const {
reed2ff1fce2014-12-11 07:07:37 -0800854#ifdef SK_DEBUG
855 int count = 0;
856 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
857 for (;;) {
858 const MCRec* rec = (const MCRec*)iter.next();
859 if (!rec) {
860 break;
861 }
862 count += 1 + rec->fDeferredSaveCount;
863 }
864 SkASSERT(count == fSaveCount);
865#endif
866 return fSaveCount;
reedf0090cb2014-11-26 08:55:51 -0800867}
868
869int SkCanvas::save() {
reed2ff1fce2014-12-11 07:07:37 -0800870 fSaveCount += 1;
871 fMCRec->fDeferredSaveCount += 1;
872 return this->getSaveCount() - 1; // return our prev value
873}
874
875void SkCanvas::doSave() {
reedf0090cb2014-11-26 08:55:51 -0800876 this->willSave();
fmalitaa62d32d2015-04-28 08:08:57 -0700877
878 SkASSERT(fMCRec->fDeferredSaveCount > 0);
879 fMCRec->fDeferredSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800880 this->internalSave();
reedf0090cb2014-11-26 08:55:51 -0800881}
882
883void SkCanvas::restore() {
reed2ff1fce2014-12-11 07:07:37 -0800884 if (fMCRec->fDeferredSaveCount > 0) {
885 SkASSERT(fSaveCount > 1);
886 fSaveCount -= 1;
887 fMCRec->fDeferredSaveCount -= 1;
888 } else {
889 // check for underflow
890 if (fMCStack.count() > 1) {
891 this->willRestore();
892 SkASSERT(fSaveCount > 1);
reeda6441162015-03-26 13:40:09 -0700893 fSaveCount -= 1;
reed2ff1fce2014-12-11 07:07:37 -0800894 this->internalRestore();
895 this->didRestore();
896 }
reedf0090cb2014-11-26 08:55:51 -0800897 }
898}
899
900void SkCanvas::restoreToCount(int count) {
901 // sanity check
902 if (count < 1) {
903 count = 1;
904 }
mtkleinf0f14112014-12-12 08:46:25 -0800905
reedf0090cb2014-11-26 08:55:51 -0800906 int n = this->getSaveCount() - count;
907 for (int i = 0; i < n; ++i) {
908 this->restore();
909 }
910}
911
reed2ff1fce2014-12-11 07:07:37 -0800912void SkCanvas::internalSave() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000913 MCRec* newTop = (MCRec*)fMCStack.push_back();
reedd9544982014-09-09 18:46:22 -0700914 new (newTop) MCRec(*fMCRec); // balanced in restore()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000915 fMCRec = newTop;
reed@google.com4b226022011-01-11 18:32:13 +0000916
reed687fa1c2015-04-07 08:00:56 -0700917 fClipStack->save();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000918}
919
reed@android.com8a1c16f2008-12-17 15:59:43 +0000920static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
reed@google.comb93ba452014-03-10 19:47:58 +0000921#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000922 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
reed@google.comb93ba452014-03-10 19:47:58 +0000923#else
924 return true;
925#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000926}
927
junov@chromium.orga907ac32012-02-24 21:54:07 +0000928bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
reed9b3aa542015-03-11 08:47:12 -0700929 SkIRect* intersection, const SkImageFilter* imageFilter) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000930 SkIRect clipBounds;
931 if (!this->getClipDeviceBounds(&clipBounds)) {
junov@chromium.orga907ac32012-02-24 21:54:07 +0000932 return false;
reed@android.comf2b98d62010-12-20 18:26:13 +0000933 }
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000934
reed96e657d2015-03-10 17:30:07 -0700935 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
936
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000937 if (imageFilter) {
reed96e657d2015-03-10 17:30:07 -0700938 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000939 }
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000940 SkIRect ir;
bsalomon49f085d2014-09-05 13:34:00 -0700941 if (bounds) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000942 SkRect r;
reed@google.com4b226022011-01-11 18:32:13 +0000943
reed96e657d2015-03-10 17:30:07 -0700944 ctm.mapRect(&r, *bounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000945 r.roundOut(&ir);
946 // early exit if the layer's bounds are clipped out
947 if (!ir.intersect(clipBounds)) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000948 if (bounds_affects_clip(flags)) {
reed9b3aa542015-03-11 08:47:12 -0700949 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -0700950 fMCRec->fRasterClip.setEmpty();
tomhudson@google.combcb671c2011-09-13 15:07:58 +0000951 }
junov@chromium.orga907ac32012-02-24 21:54:07 +0000952 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000953 }
954 } else { // no user bounds, so just use the clip
955 ir = clipBounds;
956 }
reed180aec42015-03-11 10:39:04 -0700957 SkASSERT(!ir.isEmpty());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000958
senorblanco@chromium.org89f077c2014-02-24 15:16:42 +0000959 if (bounds_affects_clip(flags)) {
reed180aec42015-03-11 10:39:04 -0700960 // Simplify the current clips since they will be applied properly during restore()
reed9b3aa542015-03-11 08:47:12 -0700961 fCachedLocalClipBoundsDirty = true;
reed687fa1c2015-04-07 08:00:56 -0700962 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
reed180aec42015-03-11 10:39:04 -0700963 fMCRec->fRasterClip.setRect(ir);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000964 }
965
966 if (intersection) {
967 *intersection = ir;
968 }
969 return true;
970}
971
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000972int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
reedd990e2f2014-12-22 11:58:30 -0800973 if (gIgnoreSaveLayerBounds) {
974 bounds = NULL;
975 }
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000976 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag);
reeda6441162015-03-26 13:40:09 -0700977 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700978 this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800979 return this->getSaveCount() - 1;
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +0000980}
981
reed2ff1fce2014-12-11 07:07:37 -0800982int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) {
reedd990e2f2014-12-22 11:58:30 -0800983 if (gIgnoreSaveLayerBounds) {
984 bounds = NULL;
985 }
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000986 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags);
reeda6441162015-03-26 13:40:09 -0700987 fSaveCount += 1;
reed76033be2015-03-14 10:54:31 -0700988 this->internalSaveLayer(bounds, paint, flags, strategy);
reed2ff1fce2014-12-11 07:07:37 -0800989 return this->getSaveCount() - 1;
reed@google.com8926b162012-03-23 15:36:36 +0000990}
991
reed2ff1fce2014-12-11 07:07:37 -0800992void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags,
reed76033be2015-03-14 10:54:31 -0700993 SaveLayerStrategy strategy) {
reed@google.comb93ba452014-03-10 19:47:58 +0000994#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
commit-bot@chromium.org2a5cd602014-05-30 20:41:20 +0000995 flags |= kClipToLayer_SaveFlag;
reed@google.comb93ba452014-03-10 19:47:58 +0000996#endif
997
junov@chromium.orga907ac32012-02-24 21:54:07 +0000998 // do this before we create the layer. We don't call the public save() since
999 // that would invoke a possibly overridden virtual
reed2ff1fce2014-12-11 07:07:37 -08001000 this->internalSave();
junov@chromium.orga907ac32012-02-24 21:54:07 +00001001
1002 fDeviceCMDirty = true;
1003
1004 SkIRect ir;
reeddaa57bf2015-05-15 10:39:17 -07001005 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) {
reed2ff1fce2014-12-11 07:07:37 -08001006 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001007 }
1008
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001009 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1010 // the clipRectBounds() call above?
1011 if (kNoLayer_SaveLayerStrategy == strategy) {
reed2ff1fce2014-12-11 07:07:37 -08001012 return;
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +00001013 }
1014
reed76033be2015-03-14 10:54:31 -07001015 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag);
reed8dc0ccb2015-03-20 06:32:52 -07001016 SkPixelGeometry geo = fProps.pixelGeometry();
1017 if (paint) {
reed76033be2015-03-14 10:54:31 -07001018 // TODO: perhaps add a query to filters so we might preserve opaqueness...
reeddaa57bf2015-05-15 10:39:17 -07001019 if (paint->getImageFilter() || paint->getColorFilter()) {
reed76033be2015-03-14 10:54:31 -07001020 isOpaque = false;
reed8dc0ccb2015-03-20 06:32:52 -07001021 geo = kUnknown_SkPixelGeometry;
reed@google.comb55deeb2012-01-06 14:43:09 +00001022 }
1023 }
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001024 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
1025 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001026
reedb2db8982014-11-13 12:41:02 -08001027 SkBaseDevice* device = this->getTopDevice();
1028 if (NULL == device) {
1029 SkDebugf("Unable to find device for layer.");
reed2ff1fce2014-12-11 07:07:37 -08001030 return;
reed@google.com76dd2772012-01-05 21:15:07 +00001031 }
reedb2db8982014-11-13 12:41:02 -08001032
reed61f501f2015-04-29 08:34:00 -07001033 bool forceSpriteOnRestore = false;
1034 {
reeddaa57bf2015-05-15 10:39:17 -07001035 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
reed61f501f2015-04-29 08:34:00 -07001036 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo);
1037 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
1038 if (NULL == newDev) {
1039 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
1040 newDev = SkBitmapDevice::Create(createInfo.fInfo);
1041 if (NULL == newDev) {
1042 SkErrorInternals::SetError(kInternalError_SkError,
1043 "Unable to create device for layer.");
1044 return;
1045 }
1046 forceSpriteOnRestore = true;
1047 }
1048 device = newDev;
bungeman@google.come25c6842011-08-17 14:53:54 +00001049 }
bsalomon@google.come97f0852011-06-17 13:10:25 +00001050
reed@google.com6f8f2922011-03-04 22:27:10 +00001051 device->setOrigin(ir.fLeft, ir.fTop);
reed61f501f2015-04-29 08:34:00 -07001052 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip,
reed86a17e72015-05-14 12:25:22 -07001053 forceSpriteOnRestore));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054 device->unref();
1055
1056 layer->fNext = fMCRec->fTopLayer;
1057 fMCRec->fLayer = layer;
1058 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059}
1060
commit-bot@chromium.orgd70fa202014-04-24 21:51:58 +00001061int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1062 return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag);
1063}
1064
reed@android.com8a1c16f2008-12-17 15:59:43 +00001065int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
1066 SaveFlags flags) {
1067 if (0xFF == alpha) {
1068 return this->saveLayer(bounds, NULL, flags);
1069 } else {
1070 SkPaint tmpPaint;
1071 tmpPaint.setAlpha(alpha);
1072 return this->saveLayer(bounds, &tmpPaint, flags);
1073 }
1074}
1075
reed@android.com8a1c16f2008-12-17 15:59:43 +00001076void SkCanvas::internalRestore() {
1077 SkASSERT(fMCStack.count() != 0);
1078
1079 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001080 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001081
reed687fa1c2015-04-07 08:00:56 -07001082 fClipStack->restore();
commit-bot@chromium.org6c157642013-08-16 00:53:34 +00001083
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001084 // reserve our layer (if any)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001085 DeviceCM* layer = fMCRec->fLayer; // may be null
1086 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1087 fMCRec->fLayer = NULL;
1088
1089 // now do the normal restore()
1090 fMCRec->~MCRec(); // balanced in save()
1091 fMCStack.pop_back();
1092 fMCRec = (MCRec*)fMCStack.back();
1093
1094 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1095 since if we're being recorded, we don't want to record this (the
1096 recorder will have already recorded the restore).
1097 */
bsalomon49f085d2014-09-05 13:34:00 -07001098 if (layer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001099 if (layer->fNext) {
reed@google.com6f8f2922011-03-04 22:27:10 +00001100 const SkIPoint& origin = layer->fDevice->getOrigin();
reed@google.com8926b162012-03-23 15:36:36 +00001101 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
reed61f501f2015-04-29 08:34:00 -07001102 layer->fPaint, layer->fDeviceIsBitmapDevice);
reed@google.com8926b162012-03-23 15:36:36 +00001103 // reset this, since internalDrawDevice will have set it to true
reed@android.com8a1c16f2008-12-17 15:59:43 +00001104 fDeviceCMDirty = true;
reedb679ca82015-04-07 04:40:48 -07001105 SkDELETE(layer);
1106 } else {
1107 // we're at the root
reeda499f902015-05-01 09:34:31 -07001108 SkASSERT(layer == (void*)fDeviceCMStorage);
reedb679ca82015-04-07 04:40:48 -07001109 layer->~DeviceCM();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001110 }
bungeman@google.com88edf1e2011-08-08 19:41:56 +00001111 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001112}
1113
reed4a8126e2014-09-22 07:29:03 -07001114SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1115 if (NULL == props) {
1116 props = &fProps;
1117 }
1118 return this->onNewSurface(info, *props);
reed@google.com76f10a32014-02-05 15:32:21 +00001119}
1120
reed4a8126e2014-09-22 07:29:03 -07001121SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
reed@google.com76f10a32014-02-05 15:32:21 +00001122 SkBaseDevice* dev = this->getDevice();
reed4a8126e2014-09-22 07:29:03 -07001123 return dev ? dev->newSurface(info, props) : NULL;
reed@google.com76f10a32014-02-05 15:32:21 +00001124}
1125
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001126SkImageInfo SkCanvas::imageInfo() const {
1127 SkBaseDevice* dev = this->getDevice();
1128 if (dev) {
1129 return dev->imageInfo();
1130 } else {
reed@google.com900ecf22014-02-20 20:55:37 +00001131 return SkImageInfo::MakeUnknown(0, 0);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001132 }
1133}
1134
1135const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1136 return this->onPeekPixels(info, rowBytes);
1137}
1138
1139const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) {
1140 SkBaseDevice* dev = this->getDevice();
1141 return dev ? dev->peekPixels(info, rowBytes) : NULL;
1142}
1143
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001144void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1145 void* pixels = this->onAccessTopLayerPixels(info, rowBytes);
1146 if (pixels && origin) {
1147 *origin = this->getTopDevice(false)->getOrigin();
1148 }
1149 return pixels;
reed@google.com9c135db2014-03-12 18:28:35 +00001150}
1151
1152void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) {
1153 SkBaseDevice* dev = this->getTopDevice();
1154 return dev ? dev->accessPixels(info, rowBytes) : NULL;
1155}
1156
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001157SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1158 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1159 if (NULL == fAddr) {
1160 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001161 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001162 return; // failure, fAddr is NULL
1163 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001164 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1165 return; // failure, fAddr is NULL
1166 }
1167 fAddr = fBitmap.getPixels();
1168 fRowBytes = fBitmap.rowBytes();
1169 }
1170 SkASSERT(fAddr); // success
1171}
1172
1173bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1174 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001175 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001176 } else {
1177 bitmap->reset();
1178 return false;
1179 }
1180}
1181
reed@android.com8a1c16f2008-12-17 15:59:43 +00001182/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001183void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001184 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001185 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001186 return;
1187 }
1188
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001189 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001190 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001191 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001192 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001193
1194 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001195
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001196 SkRect storage;
1197 const SkRect* bounds = NULL;
1198 if (paint && paint->canComputeFastBounds()) {
1199 bitmap.getBounds(&storage);
1200 matrix.mapRect(&storage);
1201 bounds = &paint->computeFastBounds(storage, &storage);
1202 }
1203
1204 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001205
1206 while (iter.next()) {
1207 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1208 }
1209
1210 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001211}
1212
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001213void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001214 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001215 SkPaint tmp;
1216 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001217 paint = &tmp;
1218 }
reed@google.com4b226022011-01-11 18:32:13 +00001219
reed@google.com8926b162012-03-23 15:36:36 +00001220 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001221 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001222 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001223 paint = &looper.paint();
1224 SkImageFilter* filter = paint->getImageFilter();
1225 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001226 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001227 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001228 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001229 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001230 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001231 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001232 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001233 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001234 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001235 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001236 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001237 SkPaint tmpUnfiltered(*paint);
1238 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001239 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1240 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001241 }
reed61f501f2015-04-29 08:34:00 -07001242 } else if (deviceIsBitmapDevice) {
1243 const SkBitmap& src = srcDev->accessBitmap(false);
1244 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001245 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001246 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001247 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001248 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001249 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001250}
1251
reed41af9662015-01-05 07:49:08 -08001252void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001253 if (gTreatSpriteAsBitmap) {
1254 this->save();
1255 this->resetMatrix();
1256 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1257 this->restore();
1258 return;
1259 }
1260
danakj9881d632014-11-26 12:41:06 -08001261 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001262 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001263 return;
1264 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001265 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001266
reed@google.com8926b162012-03-23 15:36:36 +00001267 SkPaint tmp;
1268 if (NULL == paint) {
1269 paint = &tmp;
1270 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001271
reed@google.com8926b162012-03-23 15:36:36 +00001272 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001273
reed@google.com8926b162012-03-23 15:36:36 +00001274 while (iter.next()) {
1275 paint = &looper.paint();
1276 SkImageFilter* filter = paint->getImageFilter();
1277 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1278 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001279 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001280 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001281 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001282 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001283 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001284 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001285 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001286 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001287 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001288 SkPaint tmpUnfiltered(*paint);
1289 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001290 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001291 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001292 }
1293 } else {
1294 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1295 }
1296 }
1297 LOOPER_END
1298}
1299
reed@android.com8a1c16f2008-12-17 15:59:43 +00001300/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001301void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001302 SkMatrix m;
1303 m.setTranslate(dx, dy);
1304 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001305}
1306
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001307void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001308 SkMatrix m;
1309 m.setScale(sx, sy);
1310 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001311}
1312
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001313void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001314 SkMatrix m;
1315 m.setRotate(degrees);
1316 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001317}
1318
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001319void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001320 SkMatrix m;
1321 m.setSkew(sx, sy);
1322 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001323}
1324
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001325void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001326 if (matrix.isIdentity()) {
1327 return;
1328 }
1329
reed2ff1fce2014-12-11 07:07:37 -08001330 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001331 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001332 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001333 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001334
1335 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001336}
1337
reed86a17e72015-05-14 12:25:22 -07001338void SkCanvas::setMatrix(const SkMatrix& matrix) {
1339 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001340 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001341 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001342 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001343 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001344}
1345
reed@android.com8a1c16f2008-12-17 15:59:43 +00001346void SkCanvas::resetMatrix() {
1347 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001348
reed@android.com8a1c16f2008-12-17 15:59:43 +00001349 matrix.reset();
1350 this->setMatrix(matrix);
1351}
1352
1353//////////////////////////////////////////////////////////////////////////////
1354
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001355void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001356 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001357 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1358 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001359}
1360
1361void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001362#ifdef SK_ENABLE_CLIP_QUICKREJECT
1363 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001364 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001365 return false;
1366 }
1367
reed@google.com3b3e8952012-08-16 20:53:31 +00001368 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001369 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001370 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001371
reed687fa1c2015-04-07 08:00:56 -07001372 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001373 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001374 }
1375 }
1376#endif
1377
reed@google.com5c3d1472011-02-22 19:12:23 +00001378 AutoValidateClip avc(this);
1379
reed@android.com8a1c16f2008-12-17 15:59:43 +00001380 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001381 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001382 if (!fAllowSoftClip) {
1383 edgeStyle = kHard_ClipEdgeStyle;
1384 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001385
reed1f836ee2014-07-07 07:49:34 -07001386 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001387 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001388 // the matrix. This means we don't have to a) make a path, and b) tell
1389 // the region code to scan-convert the path, only to discover that it
1390 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001391 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001392
reed1f836ee2014-07-07 07:49:34 -07001393 fMCRec->fMatrix.mapRect(&r, rect);
reed687fa1c2015-04-07 08:00:56 -07001394 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001395 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001396 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001397 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001398 // and clip against that, since it can handle any matrix. However, to
1399 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1400 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001401 SkPath path;
1402
1403 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001404 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001405 }
1406}
1407
reed73e714e2014-09-04 09:02:23 -07001408static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1409 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001410 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001411}
1412
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001413void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001414 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001415 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001416 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001417 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1418 } else {
1419 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001420 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001421}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001422
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001423void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001424 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001425 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001426 AutoValidateClip avc(this);
1427
1428 fDeviceCMDirty = true;
1429 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001430 if (!fAllowSoftClip) {
1431 edgeStyle = kHard_ClipEdgeStyle;
1432 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001433
reed687fa1c2015-04-07 08:00:56 -07001434 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001435
1436 SkPath devPath;
1437 devPath.addRRect(transformedRRect);
1438
reed73e714e2014-09-04 09:02:23 -07001439 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001440 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001441 }
1442
1443 SkPath path;
1444 path.addRRect(rrect);
1445 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001446 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001447}
1448
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001449void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001450 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001451 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1452 SkRect r;
1453 if (!path.isInverseFillType() && path.isRect(&r)) {
1454 this->onClipRect(r, op, edgeStyle);
1455 } else {
1456 this->onClipPath(path, op, edgeStyle);
1457 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001458}
1459
1460void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001461#ifdef SK_ENABLE_CLIP_QUICKREJECT
1462 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001463 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001464 return false;
1465 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001466
reed@google.com3b3e8952012-08-16 20:53:31 +00001467 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001468 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001469 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001470
reed687fa1c2015-04-07 08:00:56 -07001471 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001472 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001473 }
1474 }
1475#endif
1476
reed@google.com5c3d1472011-02-22 19:12:23 +00001477 AutoValidateClip avc(this);
1478
reed@android.com8a1c16f2008-12-17 15:59:43 +00001479 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001480 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001481 if (!fAllowSoftClip) {
1482 edgeStyle = kHard_ClipEdgeStyle;
1483 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001484
1485 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001486 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001487
reed@google.comfe701122011-11-08 19:41:23 +00001488 // Check if the transfomation, or the original path itself
1489 // made us empty. Note this can also happen if we contained NaN
1490 // values. computing the bounds detects this, and will set our
1491 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1492 if (devPath.getBounds().isEmpty()) {
1493 // resetting the path will remove any NaN or other wanky values
1494 // that might upset our scan converter.
1495 devPath.reset();
1496 }
1497
reed@google.com5c3d1472011-02-22 19:12:23 +00001498 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001499 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001500
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001501 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001502 bool clipIsAA = getClipStack()->asPath(&devPath);
1503 if (clipIsAA) {
1504 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001505 }
fmalita1a481fe2015-02-04 07:39:34 -08001506
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001507 op = SkRegion::kReplace_Op;
1508 }
1509
reed73e714e2014-09-04 09:02:23 -07001510 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001511}
1512
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001513void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001514 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001515 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001516}
1517
1518void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001519 AutoValidateClip avc(this);
1520
reed@android.com8a1c16f2008-12-17 15:59:43 +00001521 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001522 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001523
reed@google.com5c3d1472011-02-22 19:12:23 +00001524 // todo: signal fClipStack that we have a region, and therefore (I guess)
1525 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001526 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001527
reed1f836ee2014-07-07 07:49:34 -07001528 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001529}
1530
reed@google.com819c9212011-02-23 18:56:55 +00001531#ifdef SK_DEBUG
1532void SkCanvas::validateClip() const {
1533 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001534 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001535 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001536 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001537 return;
1538 }
1539
reed@google.com819c9212011-02-23 18:56:55 +00001540 SkIRect ir;
1541 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001542 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001543
reed687fa1c2015-04-07 08:00:56 -07001544 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001545 const SkClipStack::Element* element;
1546 while ((element = iter.next()) != NULL) {
1547 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001548 case SkClipStack::Element::kRect_Type:
1549 element->getRect().round(&ir);
1550 tmpClip.op(ir, element->getOp());
1551 break;
1552 case SkClipStack::Element::kEmpty_Type:
1553 tmpClip.setEmpty();
1554 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001555 default: {
1556 SkPath path;
1557 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001558 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001559 break;
1560 }
reed@google.com819c9212011-02-23 18:56:55 +00001561 }
1562 }
reed@google.com819c9212011-02-23 18:56:55 +00001563}
1564#endif
1565
reed@google.com90c07ea2012-04-13 13:50:27 +00001566void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001567 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001568 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001569
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001570 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001571 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001572 }
1573}
1574
reed@google.com5c3d1472011-02-22 19:12:23 +00001575///////////////////////////////////////////////////////////////////////////////
1576
reed@google.com754de5f2014-02-24 19:38:20 +00001577bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001578 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001579}
1580
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001581bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001582 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001583}
1584
reed@google.com3b3e8952012-08-16 20:53:31 +00001585bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001586 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001587 return true;
1588
reed1f836ee2014-07-07 07:49:34 -07001589 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001590 return true;
1591 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001592
reed1f836ee2014-07-07 07:49:34 -07001593 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001594 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001595 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001596 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001597 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001598 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001599
reed@android.coma380ae42009-07-21 01:17:02 +00001600 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001601 // TODO: should we use | instead, or compare all 4 at once?
1602 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001603 return true;
1604 }
reed@google.comc0784db2013-12-13 21:16:12 +00001605 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001606 return true;
1607 }
1608 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001609 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001610}
1611
reed@google.com3b3e8952012-08-16 20:53:31 +00001612bool SkCanvas::quickReject(const SkPath& path) const {
1613 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001614}
1615
reed@google.com3b3e8952012-08-16 20:53:31 +00001616bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001617 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001618 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001619 return false;
1620 }
1621
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001622 SkMatrix inverse;
1623 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001624 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001625 if (bounds) {
1626 bounds->setEmpty();
1627 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001628 return false;
1629 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001630
bsalomon49f085d2014-09-05 13:34:00 -07001631 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001632 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001633 // adjust it outwards in case we are antialiasing
1634 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001635
reed@google.com8f4d2302013-12-17 16:44:46 +00001636 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1637 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001638 inverse.mapRect(bounds, r);
1639 }
1640 return true;
1641}
1642
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001643bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001644 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001645 if (clip.isEmpty()) {
1646 if (bounds) {
1647 bounds->setEmpty();
1648 }
1649 return false;
1650 }
1651
bsalomon49f085d2014-09-05 13:34:00 -07001652 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001653 *bounds = clip.getBounds();
1654 }
1655 return true;
1656}
1657
reed@android.com8a1c16f2008-12-17 15:59:43 +00001658const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001659 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001660}
1661
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001662const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001663 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001664}
1665
reed@google.com9c135db2014-03-12 18:28:35 +00001666GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1667 SkBaseDevice* dev = this->getTopDevice();
1668 return dev ? dev->accessRenderTarget() : NULL;
1669}
1670
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001671GrContext* SkCanvas::getGrContext() {
1672#if SK_SUPPORT_GPU
1673 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001674 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001675 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001676 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001677 return renderTarget->getContext();
1678 }
1679 }
1680#endif
1681
1682 return NULL;
1683
1684}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001685
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001686void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1687 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001688 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001689 if (outer.isEmpty()) {
1690 return;
1691 }
1692 if (inner.isEmpty()) {
1693 this->drawRRect(outer, paint);
1694 return;
1695 }
1696
1697 // We don't have this method (yet), but technically this is what we should
1698 // be able to assert...
1699 // SkASSERT(outer.contains(inner));
1700 //
1701 // For now at least check for containment of bounds
1702 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1703
1704 this->onDrawDRRect(outer, inner, paint);
1705}
1706
reed41af9662015-01-05 07:49:08 -08001707// These need to stop being virtual -- clients need to override the onDraw... versions
1708
1709void SkCanvas::drawPaint(const SkPaint& paint) {
1710 this->onDrawPaint(paint);
1711}
1712
1713void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1714 this->onDrawRect(r, paint);
1715}
1716
1717void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1718 this->onDrawOval(r, paint);
1719}
1720
1721void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1722 this->onDrawRRect(rrect, paint);
1723}
1724
1725void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1726 this->onDrawPoints(mode, count, pts, paint);
1727}
1728
1729void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1730 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1731 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1732 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1733 indices, indexCount, paint);
1734}
1735
1736void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1737 this->onDrawPath(path, paint);
1738}
1739
reeda85d4d02015-05-06 12:56:48 -07001740void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1741 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001742}
1743
1744void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1745 const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07001746 if (dst.isEmpty()) {
1747 return;
1748 }
reed41af9662015-01-05 07:49:08 -08001749 this->onDrawImageRect(image, src, dst, paint);
1750}
1751
1752void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001753 if (bitmap.empty()) {
1754 return;
1755 }
reed41af9662015-01-05 07:49:08 -08001756 this->onDrawBitmap(bitmap, dx, dy, paint);
1757}
1758
1759void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1760 const SkPaint* paint, DrawBitmapRectFlags flags) {
tomhudson2df6fd62015-04-09 09:20:19 -07001761 if (bitmap.empty()) {
1762 return;
1763 }
reed41af9662015-01-05 07:49:08 -08001764 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1765}
1766
1767void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1768 const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001769 if (bitmap.empty()) {
1770 return;
1771 }
reed41af9662015-01-05 07:49:08 -08001772 this->onDrawBitmapNine(bitmap, center, dst, paint);
1773}
1774
1775void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001776 if (bitmap.empty()) {
1777 return;
1778 }
reed41af9662015-01-05 07:49:08 -08001779 this->onDrawSprite(bitmap, left, top, paint);
1780}
1781
reed@android.com8a1c16f2008-12-17 15:59:43 +00001782//////////////////////////////////////////////////////////////////////////////
1783// These are the virtual drawing methods
1784//////////////////////////////////////////////////////////////////////////////
1785
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001786void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001787 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001788 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1789 }
1790}
1791
reed41af9662015-01-05 07:49:08 -08001792void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001793 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001794 this->internalDrawPaint(paint);
1795}
1796
1797void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001798 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001799
1800 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001801 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001802 }
1803
reed@google.com4e2b3d32011-04-07 14:18:59 +00001804 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001805}
1806
reed41af9662015-01-05 07:49:08 -08001807void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1808 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001809 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001810 if ((long)count <= 0) {
1811 return;
1812 }
1813
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001814 SkRect r, storage;
1815 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001816 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001817 // special-case 2 points (common for drawing a single line)
1818 if (2 == count) {
1819 r.set(pts[0], pts[1]);
1820 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001821 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001822 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001823 bounds = &paint.computeFastStrokeBounds(r, &storage);
1824 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001825 return;
1826 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001827 }
reed@google.coma584aed2012-05-16 14:06:02 +00001828
reed@android.com8a1c16f2008-12-17 15:59:43 +00001829 SkASSERT(pts != NULL);
1830
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001831 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001832
reed@android.com8a1c16f2008-12-17 15:59:43 +00001833 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001834 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001835 }
reed@google.com4b226022011-01-11 18:32:13 +00001836
reed@google.com4e2b3d32011-04-07 14:18:59 +00001837 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001838}
1839
reed41af9662015-01-05 07:49:08 -08001840void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001841 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001842 SkRect storage;
1843 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001844 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001845 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1846 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1847 SkRect tmp(r);
1848 tmp.sort();
1849
1850 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001851 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001852 return;
1853 }
1854 }
reed@google.com4b226022011-01-11 18:32:13 +00001855
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001856 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001857
1858 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001859 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001860 }
1861
reed@google.com4e2b3d32011-04-07 14:18:59 +00001862 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001863}
1864
reed41af9662015-01-05 07:49:08 -08001865void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001866 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001867 SkRect storage;
1868 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001869 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001870 bounds = &paint.computeFastBounds(oval, &storage);
1871 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001872 return;
1873 }
1874 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001875
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001876 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001877
1878 while (iter.next()) {
1879 iter.fDevice->drawOval(iter, oval, looper.paint());
1880 }
1881
1882 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001883}
1884
reed41af9662015-01-05 07:49:08 -08001885void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001886 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001887 SkRect storage;
1888 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001889 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001890 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1891 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001892 return;
1893 }
1894 }
1895
1896 if (rrect.isRect()) {
1897 // call the non-virtual version
1898 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001899 return;
1900 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001901 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001902 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1903 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001904 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001905
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001906 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001907
1908 while (iter.next()) {
1909 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1910 }
1911
1912 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001913}
1914
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001915void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1916 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001917 SkRect storage;
1918 const SkRect* bounds = NULL;
1919 if (paint.canComputeFastBounds()) {
1920 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1921 if (this->quickReject(*bounds)) {
1922 return;
1923 }
1924 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001925
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001926 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001927
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001928 while (iter.next()) {
1929 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1930 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001931
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001932 LOOPER_END
1933}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001934
reed41af9662015-01-05 07:49:08 -08001935void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001936 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001937 if (!path.isFinite()) {
1938 return;
1939 }
1940
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001941 SkRect storage;
1942 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001943 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001944 const SkRect& pathBounds = path.getBounds();
1945 bounds = &paint.computeFastBounds(pathBounds, &storage);
1946 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001947 return;
1948 }
1949 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001950
1951 const SkRect& r = path.getBounds();
1952 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001953 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001954 this->internalDrawPaint(paint);
1955 }
1956 return;
1957 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001958
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001959 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001960
1961 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001962 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001963 }
1964
reed@google.com4e2b3d32011-04-07 14:18:59 +00001965 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001966}
1967
reeda85d4d02015-05-06 12:56:48 -07001968void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001969 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07001970 SkRect bounds = SkRect::MakeXYWH(x, y,
1971 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
1972 if (NULL == paint || paint->canComputeFastBounds()) {
1973 if (paint) {
1974 paint->computeFastBounds(bounds, &bounds);
1975 }
1976 if (this->quickReject(bounds)) {
1977 return;
1978 }
1979 }
1980
1981 SkLazyPaint lazy;
1982 if (NULL == paint) {
1983 paint = lazy.init();
1984 }
1985
1986 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds)
1987
1988 while (iter.next()) {
1989 iter.fDevice->drawImage(iter, image, x, y, looper.paint());
1990 }
1991
1992 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07001993}
1994
reed41af9662015-01-05 07:49:08 -08001995void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1996 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001997 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
reeda85d4d02015-05-06 12:56:48 -07001998 SkRect storage;
1999 const SkRect* bounds = &dst;
2000 if (NULL == paint || paint->canComputeFastBounds()) {
2001 if (paint) {
2002 bounds = &paint->computeFastBounds(dst, &storage);
2003 }
2004 if (this->quickReject(*bounds)) {
2005 return;
2006 }
2007 }
2008 SkLazyPaint lazy;
2009 if (NULL == paint) {
2010 paint = lazy.init();
2011 }
2012
2013 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2014
2015 while (iter.next()) {
2016 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint());
2017 }
2018
2019 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002020}
2021
reed41af9662015-01-05 07:49:08 -08002022void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002023 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002024 SkDEBUGCODE(bitmap.validate();)
2025
reed@google.com3d608122011-11-21 15:16:16 +00002026 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002027 SkRect bounds = {
2028 x, y,
2029 x + SkIntToScalar(bitmap.width()),
2030 y + SkIntToScalar(bitmap.height())
2031 };
2032 if (paint) {
2033 (void)paint->computeFastBounds(bounds, &bounds);
2034 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002035 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002036 return;
2037 }
2038 }
reed@google.com4b226022011-01-11 18:32:13 +00002039
reed@android.com8a1c16f2008-12-17 15:59:43 +00002040 SkMatrix matrix;
2041 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00002042 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002043}
2044
reed@google.com9987ec32011-09-07 11:57:52 +00002045// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002046void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002047 const SkRect& dst, const SkPaint* paint,
2048 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002049 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002050 return;
2051 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002052
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002053 SkRect storage;
2054 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00002055 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002056 if (paint) {
2057 bounds = &paint->computeFastBounds(dst, &storage);
2058 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002059 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002060 return;
2061 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002062 }
reed@google.com3d608122011-11-21 15:16:16 +00002063
reed@google.com33535f32012-09-25 15:37:50 +00002064 SkLazyPaint lazy;
2065 if (NULL == paint) {
2066 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002067 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002068
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002069 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002070
reed@google.com33535f32012-09-25 15:37:50 +00002071 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002072 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00002073 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002074
reed@google.com33535f32012-09-25 15:37:50 +00002075 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002076}
2077
reed41af9662015-01-05 07:49:08 -08002078void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2079 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08002080 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002081 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002082 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00002083}
2084
reed@google.com9987ec32011-09-07 11:57:52 +00002085void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
2086 const SkIRect& center, const SkRect& dst,
2087 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002088 if (bitmap.drawsNothing()) {
2089 return;
2090 }
reed@google.com3d608122011-11-21 15:16:16 +00002091 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00002092 SkRect storage;
2093 const SkRect* bounds = &dst;
2094 if (paint) {
2095 bounds = &paint->computeFastBounds(dst, &storage);
2096 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002097 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002098 return;
2099 }
2100 }
2101
reed@google.com9987ec32011-09-07 11:57:52 +00002102 const int32_t w = bitmap.width();
2103 const int32_t h = bitmap.height();
2104
2105 SkIRect c = center;
2106 // pin center to the bounds of the bitmap
2107 c.fLeft = SkMax32(0, center.fLeft);
2108 c.fTop = SkMax32(0, center.fTop);
2109 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2110 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2111
reed@google.com71121732012-09-18 15:14:33 +00002112 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002113 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00002114 };
2115 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002116 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00002117 };
reed@google.com9987ec32011-09-07 11:57:52 +00002118 SkScalar dstX[4] = {
2119 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2120 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2121 };
2122 SkScalar dstY[4] = {
2123 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2124 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2125 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002126
reed@google.com9987ec32011-09-07 11:57:52 +00002127 if (dstX[1] > dstX[2]) {
2128 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2129 dstX[2] = dstX[1];
2130 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002131
reed@google.com9987ec32011-09-07 11:57:52 +00002132 if (dstY[1] > dstY[2]) {
2133 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2134 dstY[2] = dstY[1];
2135 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002136
reed@google.com9987ec32011-09-07 11:57:52 +00002137 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00002138 SkRect s, d;
2139
reed@google.com9987ec32011-09-07 11:57:52 +00002140 s.fTop = srcY[y];
2141 s.fBottom = srcY[y+1];
2142 d.fTop = dstY[y];
2143 d.fBottom = dstY[y+1];
2144 for (int x = 0; x < 3; x++) {
2145 s.fLeft = srcX[x];
2146 s.fRight = srcX[x+1];
2147 d.fLeft = dstX[x];
2148 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002149 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00002150 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00002151 }
2152 }
2153}
2154
reed41af9662015-01-05 07:49:08 -08002155void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2156 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002157 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002158 SkDEBUGCODE(bitmap.validate();)
2159
2160 // Need a device entry-point, so gpu can use a mesh
2161 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2162}
2163
reed@google.comf67e4cf2011-03-15 20:56:58 +00002164class SkDeviceFilteredPaint {
2165public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002166 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002167 uint32_t filteredFlags = device->filterTextFlags(paint);
2168 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002169 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002170 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002171 fPaint = newPaint;
2172 } else {
2173 fPaint = &paint;
2174 }
2175 }
2176
reed@google.comf67e4cf2011-03-15 20:56:58 +00002177 const SkPaint& paint() const { return *fPaint; }
2178
2179private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002180 const SkPaint* fPaint;
2181 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002182};
2183
bungeman@google.com52c748b2011-08-22 21:30:43 +00002184void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2185 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002186 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002187 draw.fDevice->drawRect(draw, r, paint);
2188 } else {
2189 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002190 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002191 draw.fDevice->drawRect(draw, r, p);
2192 }
2193}
2194
2195void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2196 const char text[], size_t byteLength,
2197 SkScalar x, SkScalar y) {
2198 SkASSERT(byteLength == 0 || text != NULL);
2199
2200 // nothing to draw
2201 if (text == NULL || byteLength == 0 ||
2202 draw.fClip->isEmpty() ||
2203 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2204 return;
2205 }
2206
2207 SkScalar width = 0;
2208 SkPoint start;
2209
2210 start.set(0, 0); // to avoid warning
2211 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2212 SkPaint::kStrikeThruText_Flag)) {
2213 width = paint.measureText(text, byteLength);
2214
2215 SkScalar offsetX = 0;
2216 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2217 offsetX = SkScalarHalf(width);
2218 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2219 offsetX = width;
2220 }
2221 start.set(x - offsetX, y);
2222 }
2223
2224 if (0 == width) {
2225 return;
2226 }
2227
2228 uint32_t flags = paint.getFlags();
2229
2230 if (flags & (SkPaint::kUnderlineText_Flag |
2231 SkPaint::kStrikeThruText_Flag)) {
2232 SkScalar textSize = paint.getTextSize();
2233 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2234 SkRect r;
2235
2236 r.fLeft = start.fX;
2237 r.fRight = start.fX + width;
2238
2239 if (flags & SkPaint::kUnderlineText_Flag) {
2240 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2241 start.fY);
2242 r.fTop = offset;
2243 r.fBottom = offset + height;
2244 DrawRect(draw, paint, r, textSize);
2245 }
2246 if (flags & SkPaint::kStrikeThruText_Flag) {
2247 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2248 start.fY);
2249 r.fTop = offset;
2250 r.fBottom = offset + height;
2251 DrawRect(draw, paint, r, textSize);
2252 }
2253 }
2254}
2255
reed@google.come0d9ce82014-04-23 04:00:17 +00002256void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2257 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002258 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002259
2260 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002261 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002262 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002263 DrawTextDecorations(iter, dfp.paint(),
2264 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002265 }
2266
reed@google.com4e2b3d32011-04-07 14:18:59 +00002267 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002268}
2269
reed@google.come0d9ce82014-04-23 04:00:17 +00002270void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2271 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002272 SkPoint textOffset = SkPoint::Make(0, 0);
2273
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002274 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002275
reed@android.com8a1c16f2008-12-17 15:59:43 +00002276 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002277 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002278 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002279 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002280 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002281
reed@google.com4e2b3d32011-04-07 14:18:59 +00002282 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002283}
2284
reed@google.come0d9ce82014-04-23 04:00:17 +00002285void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2286 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002287
2288 SkPoint textOffset = SkPoint::Make(0, constY);
2289
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002290 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002291
reed@android.com8a1c16f2008-12-17 15:59:43 +00002292 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002293 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002294 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002295 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002296 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002297
reed@google.com4e2b3d32011-04-07 14:18:59 +00002298 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002299}
2300
reed@google.come0d9ce82014-04-23 04:00:17 +00002301void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2302 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002303 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002304
reed@android.com8a1c16f2008-12-17 15:59:43 +00002305 while (iter.next()) {
2306 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002307 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002308 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002309
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002310 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002311}
2312
fmalita00d5c2c2014-08-21 08:53:26 -07002313void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2314 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002315
fmalita85d5eb92015-03-04 11:20:12 -08002316 SkRect storage;
2317 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002318 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002319 storage = blob->bounds().makeOffset(x, y);
2320 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002321
fmalita85d5eb92015-03-04 11:20:12 -08002322 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002323 return;
2324 }
2325 }
2326
fmalita024f9962015-03-03 19:08:17 -08002327 // We cannot filter in the looper as we normally do, because the paint is
2328 // incomplete at this point (text-related attributes are embedded within blob run paints).
2329 SkDrawFilter* drawFilter = fMCRec->fFilter;
2330 fMCRec->fFilter = NULL;
2331
fmalita85d5eb92015-03-04 11:20:12 -08002332 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002333
fmalitaaa1b9122014-08-28 14:32:24 -07002334 while (iter.next()) {
2335 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002336 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002337 }
2338
fmalitaaa1b9122014-08-28 14:32:24 -07002339 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002340
2341 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002342}
2343
reed@google.come0d9ce82014-04-23 04:00:17 +00002344// These will become non-virtual, so they always call the (virtual) onDraw... method
2345void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2346 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002347 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002348 this->onDrawText(text, byteLength, x, y, paint);
2349}
2350void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2351 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002352 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002353 this->onDrawPosText(text, byteLength, pos, paint);
2354}
2355void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2356 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002357 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002358 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2359}
2360void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2361 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002362 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002363 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2364}
fmalita00d5c2c2014-08-21 08:53:26 -07002365void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2366 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002367 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002368 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002369 this->onDrawTextBlob(blob, x, y, paint);
2370 }
2371}
reed@google.come0d9ce82014-04-23 04:00:17 +00002372
reed41af9662015-01-05 07:49:08 -08002373void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2374 const SkPoint verts[], const SkPoint texs[],
2375 const SkColor colors[], SkXfermode* xmode,
2376 const uint16_t indices[], int indexCount,
2377 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002378 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002379 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002380
reed@android.com8a1c16f2008-12-17 15:59:43 +00002381 while (iter.next()) {
2382 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002383 colors, xmode, indices, indexCount,
2384 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002385 }
reed@google.com4b226022011-01-11 18:32:13 +00002386
reed@google.com4e2b3d32011-04-07 14:18:59 +00002387 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002388}
2389
dandovb3c9d1c2014-08-12 08:34:29 -07002390void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2391 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002392 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002393 if (NULL == cubics) {
2394 return;
2395 }
mtklein6cfa73a2014-08-13 13:33:49 -07002396
dandovecfff212014-08-04 10:02:00 -07002397 // Since a patch is always within the convex hull of the control points, we discard it when its
2398 // bounding rectangle is completely outside the current clip.
2399 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002400 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002401 if (this->quickReject(bounds)) {
2402 return;
2403 }
mtklein6cfa73a2014-08-13 13:33:49 -07002404
dandovb3c9d1c2014-08-12 08:34:29 -07002405 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2406}
2407
2408void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2409 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2410
dandovecfff212014-08-04 10:02:00 -07002411 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002412
dandovecfff212014-08-04 10:02:00 -07002413 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002414 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002415 }
mtklein6cfa73a2014-08-13 13:33:49 -07002416
dandovecfff212014-08-04 10:02:00 -07002417 LOOPER_END
2418}
2419
reed3cb38402015-02-06 08:36:15 -08002420void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002421 if (dr && !this->quickReject(dr->getBounds())) {
2422 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002423 }
2424}
2425
reed3cb38402015-02-06 08:36:15 -08002426void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002427 dr->draw(this);
2428}
2429
reed@android.com8a1c16f2008-12-17 15:59:43 +00002430//////////////////////////////////////////////////////////////////////////////
2431// These methods are NOT virtual, and therefore must call back into virtual
2432// methods, rather than actually drawing themselves.
2433//////////////////////////////////////////////////////////////////////////////
2434
2435void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002436 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002437 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002438 SkPaint paint;
2439
2440 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002441 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002442 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002443 }
2444 this->drawPaint(paint);
2445}
2446
reed@android.com845fdac2009-06-23 03:01:32 +00002447void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002448 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002449 SkPaint paint;
2450
2451 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002452 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002453 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002454 }
2455 this->drawPaint(paint);
2456}
2457
2458void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002459 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002460 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002461
reed@android.com8a1c16f2008-12-17 15:59:43 +00002462 pt.set(x, y);
2463 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2464}
2465
2466void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002467 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002468 SkPoint pt;
2469 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002470
reed@android.com8a1c16f2008-12-17 15:59:43 +00002471 pt.set(x, y);
2472 paint.setColor(color);
2473 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2474}
2475
2476void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2477 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002478 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002479 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002480
reed@android.com8a1c16f2008-12-17 15:59:43 +00002481 pts[0].set(x0, y0);
2482 pts[1].set(x1, y1);
2483 this->drawPoints(kLines_PointMode, 2, pts, paint);
2484}
2485
2486void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2487 SkScalar right, SkScalar bottom,
2488 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002489 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002490 SkRect r;
2491
2492 r.set(left, top, right, bottom);
2493 this->drawRect(r, paint);
2494}
2495
2496void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2497 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002498 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002499 if (radius < 0) {
2500 radius = 0;
2501 }
2502
2503 SkRect r;
2504 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002505 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002506}
2507
2508void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2509 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002510 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002511 if (rx > 0 && ry > 0) {
2512 if (paint.canComputeFastBounds()) {
2513 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002514 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002515 return;
2516 }
2517 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002518 SkRRect rrect;
2519 rrect.setRectXY(r, rx, ry);
2520 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002521 } else {
2522 this->drawRect(r, paint);
2523 }
2524}
2525
reed@android.com8a1c16f2008-12-17 15:59:43 +00002526void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2527 SkScalar sweepAngle, bool useCenter,
2528 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002529 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002530 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2531 this->drawOval(oval, paint);
2532 } else {
2533 SkPath path;
2534 if (useCenter) {
2535 path.moveTo(oval.centerX(), oval.centerY());
2536 }
2537 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2538 if (useCenter) {
2539 path.close();
2540 }
2541 this->drawPath(path, paint);
2542 }
2543}
2544
2545void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2546 const SkPath& path, SkScalar hOffset,
2547 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002548 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002549 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002550
reed@android.com8a1c16f2008-12-17 15:59:43 +00002551 matrix.setTranslate(hOffset, vOffset);
2552 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2553}
2554
reed@android.comf76bacf2009-05-13 14:00:33 +00002555///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002556
2557/**
2558 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2559 * against the playback cost of recursing into the subpicture to get at its actual ops.
2560 *
2561 * For now we pick a conservatively small value, though measurement (and other heuristics like
2562 * the type of ops contained) may justify changing this value.
2563 */
2564#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002565
reedd5fa1a42014-08-09 11:08:05 -07002566void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002567 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002568 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002569 if (matrix && matrix->isIdentity()) {
2570 matrix = NULL;
2571 }
reed1c2c4412015-04-30 13:09:24 -07002572 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2573 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2574 picture->playback(this);
2575 } else {
2576 this->onDrawPicture(picture, matrix, paint);
2577 }
reedd5fa1a42014-08-09 11:08:05 -07002578 }
2579}
robertphillips9b14f262014-06-04 05:40:44 -07002580
reedd5fa1a42014-08-09 11:08:05 -07002581void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2582 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002583 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002584 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002585 // Canvas has to first give the device the opportunity to render
2586 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002587 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002588 return; // the device has rendered the entire picture
2589 }
2590 }
2591
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002592 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002593 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002594}
2595
reed@android.com8a1c16f2008-12-17 15:59:43 +00002596///////////////////////////////////////////////////////////////////////////////
2597///////////////////////////////////////////////////////////////////////////////
2598
2599SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002600 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002601
2602 SkASSERT(canvas);
2603
2604 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2605 fDone = !fImpl->next();
2606}
2607
2608SkCanvas::LayerIter::~LayerIter() {
2609 fImpl->~SkDrawIter();
2610}
2611
2612void SkCanvas::LayerIter::next() {
2613 fDone = !fImpl->next();
2614}
2615
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002616SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002617 return fImpl->getDevice();
2618}
2619
2620const SkMatrix& SkCanvas::LayerIter::matrix() const {
2621 return fImpl->getMatrix();
2622}
2623
2624const SkPaint& SkCanvas::LayerIter::paint() const {
2625 const SkPaint* paint = fImpl->getPaint();
2626 if (NULL == paint) {
2627 paint = &fDefaultPaint;
2628 }
2629 return *paint;
2630}
2631
2632const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2633int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2634int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002635
2636///////////////////////////////////////////////////////////////////////////////
2637
fmalitac3b589a2014-06-05 12:40:07 -07002638SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002639
2640///////////////////////////////////////////////////////////////////////////////
2641
2642static bool supported_for_raster_canvas(const SkImageInfo& info) {
2643 switch (info.alphaType()) {
2644 case kPremul_SkAlphaType:
2645 case kOpaque_SkAlphaType:
2646 break;
2647 default:
2648 return false;
2649 }
2650
2651 switch (info.colorType()) {
2652 case kAlpha_8_SkColorType:
2653 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002654 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002655 break;
2656 default:
2657 return false;
2658 }
2659
2660 return true;
2661}
2662
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002663SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2664 if (!supported_for_raster_canvas(info)) {
2665 return NULL;
2666 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002667
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002668 SkBitmap bitmap;
2669 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2670 return NULL;
2671 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002672 return SkNEW_ARGS(SkCanvas, (bitmap));
2673}
reedd5fa1a42014-08-09 11:08:05 -07002674
2675///////////////////////////////////////////////////////////////////////////////
2676
2677SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002678 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002679 : fCanvas(canvas)
2680 , fSaveCount(canvas->getSaveCount())
2681{
bsalomon49f085d2014-09-05 13:34:00 -07002682 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002683 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002684 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002685 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002686 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002687 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002688 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002689 canvas->save();
2690 }
mtklein6cfa73a2014-08-13 13:33:49 -07002691
bsalomon49f085d2014-09-05 13:34:00 -07002692 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002693 canvas->concat(*matrix);
2694 }
2695}
2696
2697SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2698 fCanvas->restoreToCount(fSaveCount);
2699}