blob: bf4e86cafa044c9e438e36ce193088eb617982b2 [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) {
reed884e97c2015-05-26 11:31:54 -07001136 SkPixmap pmap;
1137 if (!this->onPeekPixels(&pmap)) {
1138 return NULL;
1139 }
1140 if (info) {
1141 *info = pmap.info();
1142 }
1143 if (rowBytes) {
1144 *rowBytes = pmap.rowBytes();
1145 }
1146 return pmap.addr();
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001147}
1148
reed884e97c2015-05-26 11:31:54 -07001149bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001150 SkBaseDevice* dev = this->getDevice();
reed884e97c2015-05-26 11:31:54 -07001151 return dev && dev->peekPixels(pmap);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001152}
1153
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001154void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
reed884e97c2015-05-26 11:31:54 -07001155 SkPixmap pmap;
1156 if (!this->onAccessTopLayerPixels(&pmap)) {
1157 return NULL;
1158 }
1159 if (info) {
1160 *info = pmap.info();
1161 }
1162 if (rowBytes) {
1163 *rowBytes = pmap.rowBytes();
1164 }
1165 if (origin) {
commit-bot@chromium.org6b4aaa72014-04-21 21:09:38 +00001166 *origin = this->getTopDevice(false)->getOrigin();
1167 }
reed884e97c2015-05-26 11:31:54 -07001168 return pmap.writable_addr();
reed@google.com9c135db2014-03-12 18:28:35 +00001169}
1170
reed884e97c2015-05-26 11:31:54 -07001171bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
reed@google.com9c135db2014-03-12 18:28:35 +00001172 SkBaseDevice* dev = this->getTopDevice();
reed884e97c2015-05-26 11:31:54 -07001173 return dev && dev->accessPixels(pmap);
reed@google.com9c135db2014-03-12 18:28:35 +00001174}
1175
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001176SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) {
1177 fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
1178 if (NULL == fAddr) {
1179 fInfo = canvas->imageInfo();
reed84825042014-09-02 12:50:45 -07001180 if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.tryAllocPixels(fInfo)) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001181 return; // failure, fAddr is NULL
1182 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001183 if (!canvas->readPixels(&fBitmap, 0, 0)) {
1184 return; // failure, fAddr is NULL
1185 }
1186 fAddr = fBitmap.getPixels();
1187 fRowBytes = fBitmap.rowBytes();
1188 }
1189 SkASSERT(fAddr); // success
1190}
1191
1192bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const {
1193 if (fAddr) {
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +00001194 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +00001195 } else {
1196 bitmap->reset();
1197 return false;
1198 }
1199}
1200
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201/////////////////////////////////////////////////////////////////////////////
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001202void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
reed@android.com8a1c16f2008-12-17 15:59:43 +00001203 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001204 if (bitmap.drawsNothing()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001205 return;
1206 }
1207
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001208 SkLazyPaint lazy;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001209 if (NULL == paint) {
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00001210 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001211 }
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001212
1213 SkDEBUGCODE(bitmap.validate();)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001214
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001215 SkRect storage;
1216 const SkRect* bounds = NULL;
1217 if (paint && paint->canComputeFastBounds()) {
1218 bitmap.getBounds(&storage);
1219 matrix.mapRect(&storage);
1220 bounds = &paint->computeFastBounds(storage, &storage);
1221 }
1222
1223 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00001224
1225 while (iter.next()) {
1226 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
1227 }
1228
1229 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001230}
1231
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001232void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
reed61f501f2015-04-29 08:34:00 -07001233 const SkPaint* paint, bool deviceIsBitmapDevice) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001234 SkPaint tmp;
1235 if (NULL == paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001236 paint = &tmp;
1237 }
reed@google.com4b226022011-01-11 18:32:13 +00001238
reed@google.com8926b162012-03-23 15:36:36 +00001239 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001240 while (iter.next()) {
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001241 SkBaseDevice* dstDev = iter.fDevice;
reed@google.com76dd2772012-01-05 21:15:07 +00001242 paint = &looper.paint();
1243 SkImageFilter* filter = paint->getImageFilter();
1244 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
reed@google.com8926b162012-03-23 15:36:36 +00001245 if (filter && !dstDev->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001246 SkDeviceImageFilterProxy proxy(dstDev, fProps);
reed@google.com76dd2772012-01-05 21:15:07 +00001247 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001248 SkIPoint offset = SkIPoint::Make(0, 0);
reed@google.comb55deeb2012-01-06 14:43:09 +00001249 const SkBitmap& src = srcDev->accessBitmap(false);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001250 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001251 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001252 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
senorblancobe129b22014-08-08 07:14:35 -07001253 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001254 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001255 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001256 SkPaint tmpUnfiltered(*paint);
1257 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001258 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1259 tmpUnfiltered);
reed@google.com76dd2772012-01-05 21:15:07 +00001260 }
reed61f501f2015-04-29 08:34:00 -07001261 } else if (deviceIsBitmapDevice) {
1262 const SkBitmap& src = srcDev->accessBitmap(false);
1263 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001264 } else {
reed@google.comb55deeb2012-01-06 14:43:09 +00001265 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
reed@google.com76dd2772012-01-05 21:15:07 +00001266 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001267 }
reed@google.com4e2b3d32011-04-07 14:18:59 +00001268 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001269}
1270
reed41af9662015-01-05 07:49:08 -08001271void SkCanvas::onDrawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint* paint) {
reed0acf1b42014-12-22 16:12:38 -08001272 if (gTreatSpriteAsBitmap) {
1273 this->save();
1274 this->resetMatrix();
1275 this->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
1276 this->restore();
1277 return;
1278 }
1279
danakj9881d632014-11-26 12:41:06 -08001280 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawSprite()");
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001281 if (bitmap.drawsNothing()) {
reed@google.com8926b162012-03-23 15:36:36 +00001282 return;
1283 }
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001284 SkDEBUGCODE(bitmap.validate();)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001285
reed@google.com8926b162012-03-23 15:36:36 +00001286 SkPaint tmp;
1287 if (NULL == paint) {
1288 paint = &tmp;
1289 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001290
reed@google.com8926b162012-03-23 15:36:36 +00001291 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001292
reed@google.com8926b162012-03-23 15:36:36 +00001293 while (iter.next()) {
1294 paint = &looper.paint();
1295 SkImageFilter* filter = paint->getImageFilter();
1296 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1297 if (filter && !iter.fDevice->canHandleImageFilter(filter)) {
fmalita2d97bc12014-11-20 10:44:58 -08001298 SkDeviceImageFilterProxy proxy(iter.fDevice, fProps);
reed@google.com8926b162012-03-23 15:36:36 +00001299 SkBitmap dst;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001300 SkIPoint offset = SkIPoint::Make(0, 0);
senorblanco@chromium.orgfbaea532013-08-27 21:37:01 +00001301 SkMatrix matrix = *iter.fMatrix;
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001302 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
halcanaryf622a6c2014-10-24 12:54:53 -07001303 const SkIRect clipBounds = bitmap.bounds();
senorblancobe129b22014-08-08 07:14:35 -07001304 SkAutoTUnref<SkImageFilter::Cache> cache(iter.fDevice->getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001305 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001306 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) {
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001307 SkPaint tmpUnfiltered(*paint);
1308 tmpUnfiltered.setImageFilter(NULL);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001309 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
tomhudson@google.com5efe0cb2012-04-10 19:14:48 +00001310 tmpUnfiltered);
reed@google.com8926b162012-03-23 15:36:36 +00001311 }
1312 } else {
1313 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint);
1314 }
1315 }
1316 LOOPER_END
1317}
1318
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319/////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001320void SkCanvas::translate(SkScalar dx, SkScalar dy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001321 SkMatrix m;
1322 m.setTranslate(dx, dy);
1323 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001324}
1325
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001326void SkCanvas::scale(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001327 SkMatrix m;
1328 m.setScale(sx, sy);
1329 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001330}
1331
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001332void SkCanvas::rotate(SkScalar degrees) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001333 SkMatrix m;
1334 m.setRotate(degrees);
1335 this->concat(m);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001336}
1337
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001338void SkCanvas::skew(SkScalar sx, SkScalar sy) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001339 SkMatrix m;
1340 m.setSkew(sx, sy);
1341 this->concat(m);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001342}
1343
commit-bot@chromium.org92362382014-03-18 12:51:48 +00001344void SkCanvas::concat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +00001345 if (matrix.isIdentity()) {
1346 return;
1347 }
1348
reed2ff1fce2014-12-11 07:07:37 -08001349 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001350 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001351 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001352 fMCRec->fMatrix.preConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001353
1354 this->didConcat(matrix);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001355}
1356
reed86a17e72015-05-14 12:25:22 -07001357void SkCanvas::setMatrix(const SkMatrix& matrix) {
1358 this->checkForDeferredSave();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001359 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001360 fCachedLocalClipBoundsDirty = true;
reed1f836ee2014-07-07 07:49:34 -07001361 fMCRec->fMatrix = matrix;
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +00001362 this->didSetMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001363}
1364
reed@android.com8a1c16f2008-12-17 15:59:43 +00001365void SkCanvas::resetMatrix() {
1366 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00001367
reed@android.com8a1c16f2008-12-17 15:59:43 +00001368 matrix.reset();
1369 this->setMatrix(matrix);
1370}
1371
1372//////////////////////////////////////////////////////////////////////////////
1373
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001374void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001375 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001376 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1377 this->onClipRect(rect, op, edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001378}
1379
1380void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001381#ifdef SK_ENABLE_CLIP_QUICKREJECT
1382 if (SkRegion::kIntersect_Op == op) {
reed1f836ee2014-07-07 07:49:34 -07001383 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001384 return false;
1385 }
1386
reed@google.com3b3e8952012-08-16 20:53:31 +00001387 if (this->quickReject(rect)) {
reed@google.comda17f752012-08-16 18:27:05 +00001388 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001389 fCachedLocalClipBoundsDirty = true;
reed@google.comda17f752012-08-16 18:27:05 +00001390
reed687fa1c2015-04-07 08:00:56 -07001391 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001392 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001393 }
1394 }
1395#endif
1396
reed@google.com5c3d1472011-02-22 19:12:23 +00001397 AutoValidateClip avc(this);
1398
reed@android.com8a1c16f2008-12-17 15:59:43 +00001399 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001400 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001401 if (!fAllowSoftClip) {
1402 edgeStyle = kHard_ClipEdgeStyle;
1403 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001404
reed1f836ee2014-07-07 07:49:34 -07001405 if (fMCRec->fMatrix.rectStaysRect()) {
robertphillips@google.com12367192013-10-20 13:11:16 +00001406 // for these simpler matrices, we can stay a rect even after applying
reed@android.com98de2bd2009-03-02 19:41:36 +00001407 // the matrix. This means we don't have to a) make a path, and b) tell
1408 // the region code to scan-convert the path, only to discover that it
1409 // is really just a rect.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001410 SkRect r;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001411
reed1f836ee2014-07-07 07:49:34 -07001412 fMCRec->fMatrix.mapRect(&r, rect);
reed687fa1c2015-04-07 08:00:56 -07001413 fClipStack->clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -07001414 fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001415 } else {
robertphillips@google.com12367192013-10-20 13:11:16 +00001416 // since we're rotated or some such thing, we convert the rect to a path
reed@android.com98de2bd2009-03-02 19:41:36 +00001417 // and clip against that, since it can handle any matrix. However, to
1418 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1419 // we explicitly call "our" version of clipPath.
reed@android.com8a1c16f2008-12-17 15:59:43 +00001420 SkPath path;
1421
1422 path.addRect(rect);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001423 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001424 }
1425}
1426
reed73e714e2014-09-04 09:02:23 -07001427static void rasterclip_path(SkRasterClip* rc, const SkCanvas* canvas, const SkPath& devPath,
1428 SkRegion::Op op, bool doAA) {
reedd64c9482014-09-05 17:37:38 -07001429 rc->op(devPath, canvas->getBaseLayerSize(), op, doAA);
reed@google.com819c9212011-02-23 18:56:55 +00001430}
1431
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001432void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001433 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001434 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001435 if (rrect.isRect()) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001436 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1437 } else {
1438 this->onClipRRect(rrect, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001439 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001440}
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001441
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001442void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001443 SkRRect transformedRRect;
reed1f836ee2014-07-07 07:49:34 -07001444 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001445 AutoValidateClip avc(this);
1446
1447 fDeviceCMDirty = true;
1448 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001449 if (!fAllowSoftClip) {
1450 edgeStyle = kHard_ClipEdgeStyle;
1451 }
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001452
reed687fa1c2015-04-07 08:00:56 -07001453 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001454
1455 SkPath devPath;
1456 devPath.addRRect(transformedRRect);
1457
reed73e714e2014-09-04 09:02:23 -07001458 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001459 return;
commit-bot@chromium.org14e50ae2014-02-16 23:35:31 +00001460 }
1461
1462 SkPath path;
1463 path.addRRect(rrect);
1464 // call the non-virtual version
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001465 this->SkCanvas::onClipPath(path, op, edgeStyle);
reed@google.com4ed0fb72012-12-12 20:48:18 +00001466}
1467
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001468void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
reed2ff1fce2014-12-11 07:07:37 -08001469 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001470 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1471 SkRect r;
1472 if (!path.isInverseFillType() && path.isRect(&r)) {
1473 this->onClipRect(r, op, edgeStyle);
1474 } else {
1475 this->onClipPath(path, op, edgeStyle);
1476 }
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001477}
1478
1479void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
reed@google.comda17f752012-08-16 18:27:05 +00001480#ifdef SK_ENABLE_CLIP_QUICKREJECT
1481 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
reed1f836ee2014-07-07 07:49:34 -07001482 if (fMCRec->fRasterClip.isEmpty()) {
reed@google.comda17f752012-08-16 18:27:05 +00001483 return false;
1484 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001485
reed@google.com3b3e8952012-08-16 20:53:31 +00001486 if (this->quickReject(path.getBounds())) {
reed@google.comda17f752012-08-16 18:27:05 +00001487 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001488 fCachedLocalClipBoundsDirty = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001489
reed687fa1c2015-04-07 08:00:56 -07001490 fClipStack->clipEmpty();
reed1f836ee2014-07-07 07:49:34 -07001491 return fMCRec->fRasterClip.setEmpty();
reed@google.comda17f752012-08-16 18:27:05 +00001492 }
1493 }
1494#endif
1495
reed@google.com5c3d1472011-02-22 19:12:23 +00001496 AutoValidateClip avc(this);
1497
reed@android.com8a1c16f2008-12-17 15:59:43 +00001498 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001499 fCachedLocalClipBoundsDirty = true;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001500 if (!fAllowSoftClip) {
1501 edgeStyle = kHard_ClipEdgeStyle;
1502 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001503
1504 SkPath devPath;
reed1f836ee2014-07-07 07:49:34 -07001505 path.transform(fMCRec->fMatrix, &devPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001506
reed@google.comfe701122011-11-08 19:41:23 +00001507 // Check if the transfomation, or the original path itself
1508 // made us empty. Note this can also happen if we contained NaN
1509 // values. computing the bounds detects this, and will set our
1510 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1511 if (devPath.getBounds().isEmpty()) {
1512 // resetting the path will remove any NaN or other wanky values
1513 // that might upset our scan converter.
1514 devPath.reset();
1515 }
1516
reed@google.com5c3d1472011-02-22 19:12:23 +00001517 // if we called path.swap() we could avoid a deep copy of this path
reed687fa1c2015-04-07 08:00:56 -07001518 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
reed@google.com5c3d1472011-02-22 19:12:23 +00001519
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001520 if (fAllowSimplifyClip) {
fmalita1a481fe2015-02-04 07:39:34 -08001521 bool clipIsAA = getClipStack()->asPath(&devPath);
1522 if (clipIsAA) {
1523 edgeStyle = kSoft_ClipEdgeStyle;
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001524 }
fmalita1a481fe2015-02-04 07:39:34 -08001525
caryclark@google.com45a75fb2013-04-25 13:34:40 +00001526 op = SkRegion::kReplace_Op;
1527 }
1528
reed73e714e2014-09-04 09:02:23 -07001529 rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001530}
1531
commit-bot@chromium.org759cf482014-03-06 13:18:07 +00001532void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed2ff1fce2014-12-11 07:07:37 -08001533 this->checkForDeferredSave();
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001534 this->onClipRegion(rgn, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001535}
1536
1537void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
reed@google.com5c3d1472011-02-22 19:12:23 +00001538 AutoValidateClip avc(this);
1539
reed@android.com8a1c16f2008-12-17 15:59:43 +00001540 fDeviceCMDirty = true;
reed@google.comc0784db2013-12-13 21:16:12 +00001541 fCachedLocalClipBoundsDirty = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001542
reed@google.com5c3d1472011-02-22 19:12:23 +00001543 // todo: signal fClipStack that we have a region, and therefore (I guess)
1544 // we have to ignore it, and use the region directly?
reed687fa1c2015-04-07 08:00:56 -07001545 fClipStack->clipDevRect(rgn.getBounds(), op);
reed@google.com5c3d1472011-02-22 19:12:23 +00001546
reed1f836ee2014-07-07 07:49:34 -07001547 fMCRec->fRasterClip.op(rgn, op);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001548}
1549
reed@google.com819c9212011-02-23 18:56:55 +00001550#ifdef SK_DEBUG
1551void SkCanvas::validateClip() const {
1552 // construct clipRgn from the clipstack
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00001553 const SkBaseDevice* device = this->getDevice();
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001554 if (!device) {
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001555 SkASSERT(this->isClipEmpty());
djsollen@google.comccfee2a2012-05-01 16:50:10 +00001556 return;
1557 }
1558
reed@google.com819c9212011-02-23 18:56:55 +00001559 SkIRect ir;
1560 ir.set(0, 0, device->width(), device->height());
reedd9544982014-09-09 18:46:22 -07001561 SkRasterClip tmpClip(ir, fConservativeRasterClip);
reed@google.com819c9212011-02-23 18:56:55 +00001562
reed687fa1c2015-04-07 08:00:56 -07001563 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001564 const SkClipStack::Element* element;
1565 while ((element = iter.next()) != NULL) {
1566 switch (element->getType()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001567 case SkClipStack::Element::kRect_Type:
1568 element->getRect().round(&ir);
1569 tmpClip.op(ir, element->getOp());
1570 break;
1571 case SkClipStack::Element::kEmpty_Type:
1572 tmpClip.setEmpty();
1573 break;
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001574 default: {
1575 SkPath path;
1576 element->asPath(&path);
reed73e714e2014-09-04 09:02:23 -07001577 rasterclip_path(&tmpClip, this, path, element->getOp(), element->isAA());
commit-bot@chromium.org9cb671a2014-02-16 14:45:45 +00001578 break;
1579 }
reed@google.com819c9212011-02-23 18:56:55 +00001580 }
1581 }
reed@google.com819c9212011-02-23 18:56:55 +00001582}
1583#endif
1584
reed@google.com90c07ea2012-04-13 13:50:27 +00001585void SkCanvas::replayClips(ClipVisitor* visitor) const {
reed687fa1c2015-04-07 08:00:56 -07001586 SkClipStack::B2TIter iter(*fClipStack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001587 const SkClipStack::Element* element;
reed@google.com90c07ea2012-04-13 13:50:27 +00001588
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001589 while ((element = iter.next()) != NULL) {
fmalitac3b589a2014-06-05 12:40:07 -07001590 element->replay(visitor);
reed@google.com90c07ea2012-04-13 13:50:27 +00001591 }
1592}
1593
reed@google.com5c3d1472011-02-22 19:12:23 +00001594///////////////////////////////////////////////////////////////////////////////
1595
reed@google.com754de5f2014-02-24 19:38:20 +00001596bool SkCanvas::isClipEmpty() const {
reed1f836ee2014-07-07 07:49:34 -07001597 return fMCRec->fRasterClip.isEmpty();
reed@google.com754de5f2014-02-24 19:38:20 +00001598}
1599
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001600bool SkCanvas::isClipRect() const {
reed1f836ee2014-07-07 07:49:34 -07001601 return fMCRec->fRasterClip.isRect();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001602}
1603
reed@google.com3b3e8952012-08-16 20:53:31 +00001604bool SkCanvas::quickReject(const SkRect& rect) const {
reed@google.com16078632011-12-06 18:56:37 +00001605 if (!rect.isFinite())
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +00001606 return true;
1607
reed1f836ee2014-07-07 07:49:34 -07001608 if (fMCRec->fRasterClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001609 return true;
1610 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001611
reed1f836ee2014-07-07 07:49:34 -07001612 if (fMCRec->fMatrix.hasPerspective()) {
reed@android.coma380ae42009-07-21 01:17:02 +00001613 SkRect dst;
reed1f836ee2014-07-07 07:49:34 -07001614 fMCRec->fMatrix.mapRect(&dst, rect);
reedb07a94f2014-11-19 05:03:18 -08001615 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
reed@android.coma380ae42009-07-21 01:17:02 +00001616 } else {
reed@google.comc0784db2013-12-13 21:16:12 +00001617 const SkRect& clipR = this->getLocalClipBounds();
reed@android.comd252db02009-04-01 18:31:44 +00001618
reed@android.coma380ae42009-07-21 01:17:02 +00001619 // for speed, do the most likely reject compares first
reed@google.comc0784db2013-12-13 21:16:12 +00001620 // TODO: should we use | instead, or compare all 4 at once?
1621 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
reed@android.coma380ae42009-07-21 01:17:02 +00001622 return true;
1623 }
reed@google.comc0784db2013-12-13 21:16:12 +00001624 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
reed@android.coma380ae42009-07-21 01:17:02 +00001625 return true;
1626 }
1627 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001628 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001629}
1630
reed@google.com3b3e8952012-08-16 20:53:31 +00001631bool SkCanvas::quickReject(const SkPath& path) const {
1632 return path.isEmpty() || this->quickReject(path.getBounds());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001633}
1634
reed@google.com3b3e8952012-08-16 20:53:31 +00001635bool SkCanvas::getClipBounds(SkRect* bounds) const {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001636 SkIRect ibounds;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001637 if (!this->getClipDeviceBounds(&ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001638 return false;
1639 }
1640
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001641 SkMatrix inverse;
1642 // if we can't invert the CTM, we can't return local clip bounds
reed1f836ee2014-07-07 07:49:34 -07001643 if (!fMCRec->fMatrix.invert(&inverse)) {
reed@android.com72dcd3a2009-05-18 15:46:29 +00001644 if (bounds) {
1645 bounds->setEmpty();
1646 }
reed@android.comd9c0f0b2009-02-06 22:39:37 +00001647 return false;
1648 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001649
bsalomon49f085d2014-09-05 13:34:00 -07001650 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001651 SkRect r;
reed@google.com3b3e8952012-08-16 20:53:31 +00001652 // adjust it outwards in case we are antialiasing
1653 const int inset = 1;
reed@google.comfa4d5bd2012-01-30 17:36:27 +00001654
reed@google.com8f4d2302013-12-17 16:44:46 +00001655 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1656 ibounds.fRight + inset, ibounds.fBottom + inset);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001657 inverse.mapRect(bounds, r);
1658 }
1659 return true;
1660}
1661
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001662bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
reed1f836ee2014-07-07 07:49:34 -07001663 const SkRasterClip& clip = fMCRec->fRasterClip;
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001664 if (clip.isEmpty()) {
1665 if (bounds) {
1666 bounds->setEmpty();
1667 }
1668 return false;
1669 }
1670
bsalomon49f085d2014-09-05 13:34:00 -07001671 if (bounds) {
tomhudson@google.combcb671c2011-09-13 15:07:58 +00001672 *bounds = clip.getBounds();
1673 }
1674 return true;
1675}
1676
reed@android.com8a1c16f2008-12-17 15:59:43 +00001677const SkMatrix& SkCanvas::getTotalMatrix() const {
reed1f836ee2014-07-07 07:49:34 -07001678 return fMCRec->fMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001679}
1680
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001681const SkRegion& SkCanvas::internal_private_getTotalClip() const {
reed1f836ee2014-07-07 07:49:34 -07001682 return fMCRec->fRasterClip.forceGetBW();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +00001683}
1684
reed@google.com9c135db2014-03-12 18:28:35 +00001685GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1686 SkBaseDevice* dev = this->getTopDevice();
1687 return dev ? dev->accessRenderTarget() : NULL;
1688}
1689
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001690GrContext* SkCanvas::getGrContext() {
1691#if SK_SUPPORT_GPU
1692 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07001693 if (device) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001694 GrRenderTarget* renderTarget = device->accessRenderTarget();
bsalomon49f085d2014-09-05 13:34:00 -07001695 if (renderTarget) {
commit-bot@chromium.org644629c2013-11-21 06:21:58 +00001696 return renderTarget->getContext();
1697 }
1698 }
1699#endif
1700
1701 return NULL;
1702
1703}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001704
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001705void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1706 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001707 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001708 if (outer.isEmpty()) {
1709 return;
1710 }
1711 if (inner.isEmpty()) {
1712 this->drawRRect(outer, paint);
1713 return;
1714 }
1715
1716 // We don't have this method (yet), but technically this is what we should
1717 // be able to assert...
1718 // SkASSERT(outer.contains(inner));
1719 //
1720 // For now at least check for containment of bounds
1721 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1722
1723 this->onDrawDRRect(outer, inner, paint);
1724}
1725
reed41af9662015-01-05 07:49:08 -08001726// These need to stop being virtual -- clients need to override the onDraw... versions
1727
1728void SkCanvas::drawPaint(const SkPaint& paint) {
1729 this->onDrawPaint(paint);
1730}
1731
1732void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1733 this->onDrawRect(r, paint);
1734}
1735
1736void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1737 this->onDrawOval(r, paint);
1738}
1739
1740void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1741 this->onDrawRRect(rrect, paint);
1742}
1743
1744void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1745 this->onDrawPoints(mode, count, pts, paint);
1746}
1747
1748void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1749 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1750 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1751 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1752 indices, indexCount, paint);
1753}
1754
1755void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1756 this->onDrawPath(path, paint);
1757}
1758
reeda85d4d02015-05-06 12:56:48 -07001759void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1760 this->onDrawImage(image, x, y, paint);
reed41af9662015-01-05 07:49:08 -08001761}
1762
1763void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1764 const SkPaint* paint) {
reeda85d4d02015-05-06 12:56:48 -07001765 if (dst.isEmpty()) {
1766 return;
1767 }
reed41af9662015-01-05 07:49:08 -08001768 this->onDrawImageRect(image, src, dst, paint);
1769}
1770
1771void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001772 if (bitmap.empty()) {
1773 return;
1774 }
reed41af9662015-01-05 07:49:08 -08001775 this->onDrawBitmap(bitmap, dx, dy, paint);
1776}
1777
1778void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1779 const SkPaint* paint, DrawBitmapRectFlags flags) {
tomhudson2df6fd62015-04-09 09:20:19 -07001780 if (bitmap.empty()) {
1781 return;
1782 }
reed41af9662015-01-05 07:49:08 -08001783 this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
1784}
1785
1786void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1787 const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001788 if (bitmap.empty()) {
1789 return;
1790 }
reed41af9662015-01-05 07:49:08 -08001791 this->onDrawBitmapNine(bitmap, center, dst, paint);
1792}
1793
1794void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
tomhudson2df6fd62015-04-09 09:20:19 -07001795 if (bitmap.empty()) {
1796 return;
1797 }
reed41af9662015-01-05 07:49:08 -08001798 this->onDrawSprite(bitmap, left, top, paint);
1799}
1800
reed@android.com8a1c16f2008-12-17 15:59:43 +00001801//////////////////////////////////////////////////////////////////////////////
1802// These are the virtual drawing methods
1803//////////////////////////////////////////////////////////////////////////////
1804
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001805void SkCanvas::onDiscard() {
bsalomon49f085d2014-09-05 13:34:00 -07001806 if (fSurfaceBase) {
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001807 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
1808 }
1809}
1810
reed41af9662015-01-05 07:49:08 -08001811void SkCanvas::onDrawPaint(const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001812 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001813 this->internalDrawPaint(paint);
1814}
1815
1816void SkCanvas::internalDrawPaint(const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001817 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001818
1819 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001820 iter.fDevice->drawPaint(iter, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001821 }
1822
reed@google.com4e2b3d32011-04-07 14:18:59 +00001823 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001824}
1825
reed41af9662015-01-05 07:49:08 -08001826void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
1827 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001828 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001829 if ((long)count <= 0) {
1830 return;
1831 }
1832
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001833 SkRect r, storage;
1834 const SkRect* bounds = NULL;
reed@google.coma584aed2012-05-16 14:06:02 +00001835 if (paint.canComputeFastBounds()) {
reed@google.coma584aed2012-05-16 14:06:02 +00001836 // special-case 2 points (common for drawing a single line)
1837 if (2 == count) {
1838 r.set(pts[0], pts[1]);
1839 } else {
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001840 r.set(pts, SkToInt(count));
reed@google.coma584aed2012-05-16 14:06:02 +00001841 }
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001842 bounds = &paint.computeFastStrokeBounds(r, &storage);
1843 if (this->quickReject(*bounds)) {
reed@google.coma584aed2012-05-16 14:06:02 +00001844 return;
1845 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001846 }
reed@google.coma584aed2012-05-16 14:06:02 +00001847
reed@android.com8a1c16f2008-12-17 15:59:43 +00001848 SkASSERT(pts != NULL);
1849
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001850 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
reed@google.com4b226022011-01-11 18:32:13 +00001851
reed@android.com8a1c16f2008-12-17 15:59:43 +00001852 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001853 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001854 }
reed@google.com4b226022011-01-11 18:32:13 +00001855
reed@google.com4e2b3d32011-04-07 14:18:59 +00001856 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001857}
1858
reed41af9662015-01-05 07:49:08 -08001859void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001860 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001861 SkRect storage;
1862 const SkRect* bounds = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001863 if (paint.canComputeFastBounds()) {
reed84328082015-02-10 14:18:09 -08001864 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
1865 // To prevent accidental rejecting at this stage, we have to sort it before we check.
1866 SkRect tmp(r);
1867 tmp.sort();
1868
1869 bounds = &paint.computeFastBounds(tmp, &storage);
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001870 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001871 return;
1872 }
1873 }
reed@google.com4b226022011-01-11 18:32:13 +00001874
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001875 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001876
1877 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001878 iter.fDevice->drawRect(iter, r, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001879 }
1880
reed@google.com4e2b3d32011-04-07 14:18:59 +00001881 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001882}
1883
reed41af9662015-01-05 07:49:08 -08001884void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001885 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001886 SkRect storage;
1887 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001888 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001889 bounds = &paint.computeFastBounds(oval, &storage);
1890 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001891 return;
1892 }
1893 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +00001894
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001895 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001896
1897 while (iter.next()) {
1898 iter.fDevice->drawOval(iter, oval, looper.paint());
1899 }
1900
1901 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001902}
1903
reed41af9662015-01-05 07:49:08 -08001904void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001905 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001906 SkRect storage;
1907 const SkRect* bounds = NULL;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001908 if (paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001909 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage);
1910 if (this->quickReject(*bounds)) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001911 return;
1912 }
1913 }
1914
1915 if (rrect.isRect()) {
1916 // call the non-virtual version
1917 this->SkCanvas::drawRect(rrect.getBounds(), paint);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001918 return;
1919 } else if (rrect.isOval()) {
reed@google.com4ed0fb72012-12-12 20:48:18 +00001920 // call the non-virtual version
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001921 this->SkCanvas::drawOval(rrect.getBounds(), paint);
1922 return;
reed@google.com4ed0fb72012-12-12 20:48:18 +00001923 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001924
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001925 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001926
1927 while (iter.next()) {
1928 iter.fDevice->drawRRect(iter, rrect, looper.paint());
1929 }
1930
1931 LOOPER_END
reed@google.com4ed0fb72012-12-12 20:48:18 +00001932}
1933
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001934void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1935 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001936 SkRect storage;
1937 const SkRect* bounds = NULL;
1938 if (paint.canComputeFastBounds()) {
1939 bounds = &paint.computeFastBounds(outer.getBounds(), &storage);
1940 if (this->quickReject(*bounds)) {
1941 return;
1942 }
1943 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001944
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001945 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001946
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001947 while (iter.next()) {
1948 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
1949 }
skia.committer@gmail.com25c71272014-02-21 03:02:02 +00001950
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +00001951 LOOPER_END
1952}
reed@google.com4ed0fb72012-12-12 20:48:18 +00001953
reed41af9662015-01-05 07:49:08 -08001954void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08001955 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
reed@google.com93645112012-07-26 16:11:47 +00001956 if (!path.isFinite()) {
1957 return;
1958 }
1959
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001960 SkRect storage;
1961 const SkRect* bounds = NULL;
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001962 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001963 const SkRect& pathBounds = path.getBounds();
1964 bounds = &paint.computeFastBounds(pathBounds, &storage);
1965 if (this->quickReject(*bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001966 return;
1967 }
1968 }
commit-bot@chromium.org0b45dc42014-02-21 05:42:57 +00001969
1970 const SkRect& r = path.getBounds();
1971 if (r.width() <= 0 && r.height() <= 0) {
commit-bot@chromium.org6803c212014-05-04 18:08:27 +00001972 if (path.isInverseFillType()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001973 this->internalDrawPaint(paint);
1974 }
1975 return;
1976 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001977
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00001978 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
reed@android.com8a1c16f2008-12-17 15:59:43 +00001979
1980 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00001981 iter.fDevice->drawPath(iter, path, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001982 }
1983
reed@google.com4e2b3d32011-04-07 14:18:59 +00001984 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00001985}
1986
reeda85d4d02015-05-06 12:56:48 -07001987void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08001988 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
reeda85d4d02015-05-06 12:56:48 -07001989 SkRect bounds = SkRect::MakeXYWH(x, y,
1990 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
1991 if (NULL == paint || paint->canComputeFastBounds()) {
1992 if (paint) {
1993 paint->computeFastBounds(bounds, &bounds);
1994 }
1995 if (this->quickReject(bounds)) {
1996 return;
1997 }
1998 }
1999
2000 SkLazyPaint lazy;
2001 if (NULL == paint) {
2002 paint = lazy.init();
2003 }
2004
2005 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &bounds)
2006
2007 while (iter.next()) {
2008 iter.fDevice->drawImage(iter, image, x, y, looper.paint());
2009 }
2010
2011 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002012}
2013
reed41af9662015-01-05 07:49:08 -08002014void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2015 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002016 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
reeda85d4d02015-05-06 12:56:48 -07002017 SkRect storage;
2018 const SkRect* bounds = &dst;
2019 if (NULL == paint || paint->canComputeFastBounds()) {
2020 if (paint) {
2021 bounds = &paint->computeFastBounds(dst, &storage);
2022 }
2023 if (this->quickReject(*bounds)) {
2024 return;
2025 }
2026 }
2027 SkLazyPaint lazy;
2028 if (NULL == paint) {
2029 paint = lazy.init();
2030 }
2031
2032 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
2033
2034 while (iter.next()) {
2035 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint());
2036 }
2037
2038 LOOPER_END
piotaixrb5fae932014-09-24 13:03:30 -07002039}
2040
reed41af9662015-01-05 07:49:08 -08002041void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002042 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002043 SkDEBUGCODE(bitmap.validate();)
2044
reed@google.com3d608122011-11-21 15:16:16 +00002045 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002046 SkRect bounds = {
2047 x, y,
2048 x + SkIntToScalar(bitmap.width()),
2049 y + SkIntToScalar(bitmap.height())
2050 };
2051 if (paint) {
2052 (void)paint->computeFastBounds(bounds, &bounds);
2053 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002054 if (this->quickReject(bounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002055 return;
2056 }
2057 }
reed@google.com4b226022011-01-11 18:32:13 +00002058
reed@android.com8a1c16f2008-12-17 15:59:43 +00002059 SkMatrix matrix;
2060 matrix.setTranslate(x, y);
robertphillips@google.com9bf380c2013-07-25 12:10:42 +00002061 this->internalDrawBitmap(bitmap, matrix, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002062}
2063
reed@google.com9987ec32011-09-07 11:57:52 +00002064// this one is non-virtual, so it can be called safely by other canvas apis
reed@google.com71121732012-09-18 15:14:33 +00002065void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002066 const SkRect& dst, const SkPaint* paint,
2067 DrawBitmapRectFlags flags) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002068 if (bitmap.drawsNothing() || dst.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002069 return;
2070 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002071
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002072 SkRect storage;
2073 const SkRect* bounds = &dst;
reed@google.com3d608122011-11-21 15:16:16 +00002074 if (NULL == paint || paint->canComputeFastBounds()) {
reed@google.com9efd9a02012-01-30 15:41:43 +00002075 if (paint) {
2076 bounds = &paint->computeFastBounds(dst, &storage);
2077 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002078 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002079 return;
2080 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00002081 }
reed@google.com3d608122011-11-21 15:16:16 +00002082
reed@google.com33535f32012-09-25 15:37:50 +00002083 SkLazyPaint lazy;
2084 if (NULL == paint) {
2085 paint = lazy.init();
reed@android.com8a1c16f2008-12-17 15:59:43 +00002086 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002087
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002088 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002089
reed@google.com33535f32012-09-25 15:37:50 +00002090 while (iter.next()) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002091 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags);
reed@android.comf2b98d62010-12-20 18:26:13 +00002092 }
skia.committer@gmail.com7064e9a2012-09-26 02:01:18 +00002093
reed@google.com33535f32012-09-25 15:37:50 +00002094 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002095}
2096
reed41af9662015-01-05 07:49:08 -08002097void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2098 const SkPaint* paint, DrawBitmapRectFlags flags) {
danakj9881d632014-11-26 12:41:06 -08002099 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
reed@google.com9987ec32011-09-07 11:57:52 +00002100 SkDEBUGCODE(bitmap.validate();)
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002101 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
reed@google.com9987ec32011-09-07 11:57:52 +00002102}
2103
reed@google.com9987ec32011-09-07 11:57:52 +00002104void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
2105 const SkIRect& center, const SkRect& dst,
2106 const SkPaint* paint) {
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00002107 if (bitmap.drawsNothing()) {
2108 return;
2109 }
reed@google.com3d608122011-11-21 15:16:16 +00002110 if (NULL == paint || paint->canComputeFastBounds()) {
djsollen@google.com60abb072012-02-15 18:49:15 +00002111 SkRect storage;
2112 const SkRect* bounds = &dst;
2113 if (paint) {
2114 bounds = &paint->computeFastBounds(dst, &storage);
2115 }
reed@google.com3b3e8952012-08-16 20:53:31 +00002116 if (this->quickReject(*bounds)) {
reed@google.com3d608122011-11-21 15:16:16 +00002117 return;
2118 }
2119 }
2120
reed@google.com9987ec32011-09-07 11:57:52 +00002121 const int32_t w = bitmap.width();
2122 const int32_t h = bitmap.height();
2123
2124 SkIRect c = center;
2125 // pin center to the bounds of the bitmap
2126 c.fLeft = SkMax32(0, center.fLeft);
2127 c.fTop = SkMax32(0, center.fTop);
2128 c.fRight = SkPin32(center.fRight, c.fLeft, w);
2129 c.fBottom = SkPin32(center.fBottom, c.fTop, h);
2130
reed@google.com71121732012-09-18 15:14:33 +00002131 const SkScalar srcX[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002132 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
reed@google.com71121732012-09-18 15:14:33 +00002133 };
2134 const SkScalar srcY[4] = {
rmistry@google.com7d474f82013-01-02 22:03:54 +00002135 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
reed@google.com71121732012-09-18 15:14:33 +00002136 };
reed@google.com9987ec32011-09-07 11:57:52 +00002137 SkScalar dstX[4] = {
2138 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
2139 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
2140 };
2141 SkScalar dstY[4] = {
2142 dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
2143 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
2144 };
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002145
reed@google.com9987ec32011-09-07 11:57:52 +00002146 if (dstX[1] > dstX[2]) {
2147 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
2148 dstX[2] = dstX[1];
2149 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002150
reed@google.com9987ec32011-09-07 11:57:52 +00002151 if (dstY[1] > dstY[2]) {
2152 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
2153 dstY[2] = dstY[1];
2154 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +00002155
reed@google.com9987ec32011-09-07 11:57:52 +00002156 for (int y = 0; y < 3; y++) {
reed@google.com71121732012-09-18 15:14:33 +00002157 SkRect s, d;
2158
reed@google.com9987ec32011-09-07 11:57:52 +00002159 s.fTop = srcY[y];
2160 s.fBottom = srcY[y+1];
2161 d.fTop = dstY[y];
2162 d.fBottom = dstY[y+1];
2163 for (int x = 0; x < 3; x++) {
2164 s.fLeft = srcX[x];
2165 s.fRight = srcX[x+1];
2166 d.fLeft = dstX[x];
2167 d.fRight = dstX[x+1];
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +00002168 this->internalDrawBitmapRect(bitmap, &s, d, paint,
robertphillips@google.com31acc112013-08-20 12:13:48 +00002169 kNone_DrawBitmapRectFlag);
reed@google.com9987ec32011-09-07 11:57:52 +00002170 }
2171 }
2172}
2173
reed41af9662015-01-05 07:49:08 -08002174void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2175 const SkPaint* paint) {
danakj9881d632014-11-26 12:41:06 -08002176 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
reed@google.com9987ec32011-09-07 11:57:52 +00002177 SkDEBUGCODE(bitmap.validate();)
2178
2179 // Need a device entry-point, so gpu can use a mesh
2180 this->internalDrawBitmapNine(bitmap, center, dst, paint);
2181}
2182
reed@google.comf67e4cf2011-03-15 20:56:58 +00002183class SkDeviceFilteredPaint {
2184public:
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002185 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
fmalita112e7e22014-11-13 14:05:58 -08002186 uint32_t filteredFlags = device->filterTextFlags(paint);
2187 if (filteredFlags != paint.getFlags()) {
reed@google.coma076e9b2011-04-06 20:17:29 +00002188 SkPaint* newPaint = fLazy.set(paint);
fmalita112e7e22014-11-13 14:05:58 -08002189 newPaint->setFlags(filteredFlags);
reed@google.comf67e4cf2011-03-15 20:56:58 +00002190 fPaint = newPaint;
2191 } else {
2192 fPaint = &paint;
2193 }
2194 }
2195
reed@google.comf67e4cf2011-03-15 20:56:58 +00002196 const SkPaint& paint() const { return *fPaint; }
2197
2198private:
mike@reedtribe.org2c8fc5a2011-04-10 00:35:29 +00002199 const SkPaint* fPaint;
2200 SkLazyPaint fLazy;
reed@google.comf67e4cf2011-03-15 20:56:58 +00002201};
2202
bungeman@google.com52c748b2011-08-22 21:30:43 +00002203void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2204 const SkRect& r, SkScalar textSize) {
epoger@google.com17b78942011-08-26 14:40:38 +00002205 if (paint.getStyle() == SkPaint::kFill_Style) {
bungeman@google.com52c748b2011-08-22 21:30:43 +00002206 draw.fDevice->drawRect(draw, r, paint);
2207 } else {
2208 SkPaint p(paint);
epoger@google.com17b78942011-08-26 14:40:38 +00002209 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
bungeman@google.com52c748b2011-08-22 21:30:43 +00002210 draw.fDevice->drawRect(draw, r, p);
2211 }
2212}
2213
2214void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2215 const char text[], size_t byteLength,
2216 SkScalar x, SkScalar y) {
2217 SkASSERT(byteLength == 0 || text != NULL);
2218
2219 // nothing to draw
2220 if (text == NULL || byteLength == 0 ||
2221 draw.fClip->isEmpty() ||
2222 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2223 return;
2224 }
2225
2226 SkScalar width = 0;
2227 SkPoint start;
2228
2229 start.set(0, 0); // to avoid warning
2230 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2231 SkPaint::kStrikeThruText_Flag)) {
2232 width = paint.measureText(text, byteLength);
2233
2234 SkScalar offsetX = 0;
2235 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2236 offsetX = SkScalarHalf(width);
2237 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2238 offsetX = width;
2239 }
2240 start.set(x - offsetX, y);
2241 }
2242
2243 if (0 == width) {
2244 return;
2245 }
2246
2247 uint32_t flags = paint.getFlags();
2248
2249 if (flags & (SkPaint::kUnderlineText_Flag |
2250 SkPaint::kStrikeThruText_Flag)) {
2251 SkScalar textSize = paint.getTextSize();
2252 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2253 SkRect r;
2254
2255 r.fLeft = start.fX;
2256 r.fRight = start.fX + width;
2257
2258 if (flags & SkPaint::kUnderlineText_Flag) {
2259 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2260 start.fY);
2261 r.fTop = offset;
2262 r.fBottom = offset + height;
2263 DrawRect(draw, paint, r, textSize);
2264 }
2265 if (flags & SkPaint::kStrikeThruText_Flag) {
2266 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2267 start.fY);
2268 r.fTop = offset;
2269 r.fBottom = offset + height;
2270 DrawRect(draw, paint, r, textSize);
2271 }
2272 }
2273}
2274
reed@google.come0d9ce82014-04-23 04:00:17 +00002275void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2276 const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002277 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +00002278
2279 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002280 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
reed@google.comf67e4cf2011-03-15 20:56:58 +00002281 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
bungeman@google.com52c748b2011-08-22 21:30:43 +00002282 DrawTextDecorations(iter, dfp.paint(),
2283 static_cast<const char*>(text), byteLength, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002284 }
2285
reed@google.com4e2b3d32011-04-07 14:18:59 +00002286 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002287}
2288
reed@google.come0d9ce82014-04-23 04:00:17 +00002289void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2290 const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002291 SkPoint textOffset = SkPoint::Make(0, 0);
2292
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002293 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002294
reed@android.com8a1c16f2008-12-17 15:59:43 +00002295 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002296 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002297 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002298 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002299 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002300
reed@google.com4e2b3d32011-04-07 14:18:59 +00002301 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002302}
2303
reed@google.come0d9ce82014-04-23 04:00:17 +00002304void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2305 SkScalar constY, const SkPaint& paint) {
fmalita05c4a432014-09-29 06:29:53 -07002306
2307 SkPoint textOffset = SkPoint::Make(0, constY);
2308
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002309 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002310
reed@android.com8a1c16f2008-12-17 15:59:43 +00002311 while (iter.next()) {
reed@google.com4e2b3d32011-04-07 14:18:59 +00002312 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita05c4a432014-09-29 06:29:53 -07002313 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
reed@google.comf67e4cf2011-03-15 20:56:58 +00002314 dfp.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002315 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002316
reed@google.com4e2b3d32011-04-07 14:18:59 +00002317 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002318}
2319
reed@google.come0d9ce82014-04-23 04:00:17 +00002320void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2321 const SkMatrix* matrix, const SkPaint& paint) {
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002322 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00002323
reed@android.com8a1c16f2008-12-17 15:59:43 +00002324 while (iter.next()) {
2325 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002326 matrix, looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002327 }
skia.committer@gmail.comb0430d02014-04-24 03:05:07 +00002328
commit-bot@chromium.org945ec3a2014-04-22 20:07:30 +00002329 LOOPER_END
commit-bot@chromium.org4325d112014-04-22 19:03:02 +00002330}
2331
fmalita00d5c2c2014-08-21 08:53:26 -07002332void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2333 const SkPaint& paint) {
fmalita7ba7aa72014-08-29 09:46:36 -07002334
fmalita85d5eb92015-03-04 11:20:12 -08002335 SkRect storage;
2336 const SkRect* bounds = NULL;
fmalita19653d12014-10-16 11:53:30 -07002337 if (paint.canComputeFastBounds()) {
fmalita85d5eb92015-03-04 11:20:12 -08002338 storage = blob->bounds().makeOffset(x, y);
2339 bounds = &paint.computeFastBounds(storage, &storage);
fmalita7ba7aa72014-08-29 09:46:36 -07002340
fmalita85d5eb92015-03-04 11:20:12 -08002341 if (this->quickReject(*bounds)) {
fmalita7ba7aa72014-08-29 09:46:36 -07002342 return;
2343 }
2344 }
2345
fmalita024f9962015-03-03 19:08:17 -08002346 // We cannot filter in the looper as we normally do, because the paint is
2347 // incomplete at this point (text-related attributes are embedded within blob run paints).
2348 SkDrawFilter* drawFilter = fMCRec->fFilter;
2349 fMCRec->fFilter = NULL;
2350
fmalita85d5eb92015-03-04 11:20:12 -08002351 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
fmalita00d5c2c2014-08-21 08:53:26 -07002352
fmalitaaa1b9122014-08-28 14:32:24 -07002353 while (iter.next()) {
2354 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
fmalita024f9962015-03-03 19:08:17 -08002355 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
fmalita00d5c2c2014-08-21 08:53:26 -07002356 }
2357
fmalitaaa1b9122014-08-28 14:32:24 -07002358 LOOPER_END
fmalita024f9962015-03-03 19:08:17 -08002359
2360 fMCRec->fFilter = drawFilter;
fmalita00d5c2c2014-08-21 08:53:26 -07002361}
2362
reed@google.come0d9ce82014-04-23 04:00:17 +00002363// These will become non-virtual, so they always call the (virtual) onDraw... method
2364void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2365 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002366 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002367 this->onDrawText(text, byteLength, x, y, paint);
2368}
2369void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2370 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002371 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002372 this->onDrawPosText(text, byteLength, pos, paint);
2373}
2374void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2375 SkScalar constY, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002376 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002377 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2378}
2379void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2380 const SkMatrix* matrix, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002381 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
reed@google.come0d9ce82014-04-23 04:00:17 +00002382 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2383}
fmalita00d5c2c2014-08-21 08:53:26 -07002384void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2385 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002386 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
bsalomon49f085d2014-09-05 13:34:00 -07002387 if (blob) {
fmalita00d5c2c2014-08-21 08:53:26 -07002388 this->onDrawTextBlob(blob, x, y, paint);
2389 }
2390}
reed@google.come0d9ce82014-04-23 04:00:17 +00002391
reed41af9662015-01-05 07:49:08 -08002392void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2393 const SkPoint verts[], const SkPoint texs[],
2394 const SkColor colors[], SkXfermode* xmode,
2395 const uint16_t indices[], int indexCount,
2396 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002397 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
senorblanco@chromium.org78cf1192014-01-28 19:22:35 +00002398 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
reed@google.com4b226022011-01-11 18:32:13 +00002399
reed@android.com8a1c16f2008-12-17 15:59:43 +00002400 while (iter.next()) {
2401 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
reed@google.com4e2b3d32011-04-07 14:18:59 +00002402 colors, xmode, indices, indexCount,
2403 looper.paint());
reed@android.com8a1c16f2008-12-17 15:59:43 +00002404 }
reed@google.com4b226022011-01-11 18:32:13 +00002405
reed@google.com4e2b3d32011-04-07 14:18:59 +00002406 LOOPER_END
reed@android.com8a1c16f2008-12-17 15:59:43 +00002407}
2408
dandovb3c9d1c2014-08-12 08:34:29 -07002409void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2410 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002411 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
dandovb3c9d1c2014-08-12 08:34:29 -07002412 if (NULL == cubics) {
2413 return;
2414 }
mtklein6cfa73a2014-08-13 13:33:49 -07002415
dandovecfff212014-08-04 10:02:00 -07002416 // Since a patch is always within the convex hull of the control points, we discard it when its
2417 // bounding rectangle is completely outside the current clip.
2418 SkRect bounds;
dandovb3c9d1c2014-08-12 08:34:29 -07002419 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
dandovecfff212014-08-04 10:02:00 -07002420 if (this->quickReject(bounds)) {
2421 return;
2422 }
mtklein6cfa73a2014-08-13 13:33:49 -07002423
dandovb3c9d1c2014-08-12 08:34:29 -07002424 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2425}
2426
2427void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2428 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2429
dandovecfff212014-08-04 10:02:00 -07002430 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
mtklein6cfa73a2014-08-13 13:33:49 -07002431
dandovecfff212014-08-04 10:02:00 -07002432 while (iter.next()) {
dandovb3c9d1c2014-08-12 08:34:29 -07002433 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
dandovecfff212014-08-04 10:02:00 -07002434 }
mtklein6cfa73a2014-08-13 13:33:49 -07002435
dandovecfff212014-08-04 10:02:00 -07002436 LOOPER_END
2437}
2438
reed3cb38402015-02-06 08:36:15 -08002439void SkCanvas::drawDrawable(SkDrawable* dr) {
reed6be2aa92014-11-18 11:08:05 -08002440 if (dr && !this->quickReject(dr->getBounds())) {
2441 this->onDrawDrawable(dr);
reed6a070dc2014-11-11 19:36:09 -08002442 }
2443}
2444
reed3cb38402015-02-06 08:36:15 -08002445void SkCanvas::onDrawDrawable(SkDrawable* dr) {
reed6a070dc2014-11-11 19:36:09 -08002446 dr->draw(this);
2447}
2448
reed@android.com8a1c16f2008-12-17 15:59:43 +00002449//////////////////////////////////////////////////////////////////////////////
2450// These methods are NOT virtual, and therefore must call back into virtual
2451// methods, rather than actually drawing themselves.
2452//////////////////////////////////////////////////////////////////////////////
2453
2454void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
reed@android.com845fdac2009-06-23 03:01:32 +00002455 SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002456 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002457 SkPaint paint;
2458
2459 paint.setARGB(a, r, g, b);
reed@android.com845fdac2009-06-23 03:01:32 +00002460 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002461 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002462 }
2463 this->drawPaint(paint);
2464}
2465
reed@android.com845fdac2009-06-23 03:01:32 +00002466void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
danakj9881d632014-11-26 12:41:06 -08002467 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002468 SkPaint paint;
2469
2470 paint.setColor(c);
reed@android.com845fdac2009-06-23 03:01:32 +00002471 if (SkXfermode::kSrcOver_Mode != mode) {
reed@android.com0baf1932009-06-24 12:41:42 +00002472 paint.setXfermodeMode(mode);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002473 }
2474 this->drawPaint(paint);
2475}
2476
2477void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002478 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002479 SkPoint pt;
reed@google.com4b226022011-01-11 18:32:13 +00002480
reed@android.com8a1c16f2008-12-17 15:59:43 +00002481 pt.set(x, y);
2482 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2483}
2484
2485void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
danakj9881d632014-11-26 12:41:06 -08002486 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002487 SkPoint pt;
2488 SkPaint paint;
reed@google.com4b226022011-01-11 18:32:13 +00002489
reed@android.com8a1c16f2008-12-17 15:59:43 +00002490 pt.set(x, y);
2491 paint.setColor(color);
2492 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2493}
2494
2495void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2496 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002497 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002498 SkPoint pts[2];
reed@google.com4b226022011-01-11 18:32:13 +00002499
reed@android.com8a1c16f2008-12-17 15:59:43 +00002500 pts[0].set(x0, y0);
2501 pts[1].set(x1, y1);
2502 this->drawPoints(kLines_PointMode, 2, pts, paint);
2503}
2504
2505void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2506 SkScalar right, SkScalar bottom,
2507 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002508 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002509 SkRect r;
2510
2511 r.set(left, top, right, bottom);
2512 this->drawRect(r, paint);
2513}
2514
2515void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2516 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002517 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002518 if (radius < 0) {
2519 radius = 0;
2520 }
2521
2522 SkRect r;
2523 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
reed@google.com4ed0fb72012-12-12 20:48:18 +00002524 this->drawOval(r, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002525}
2526
2527void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2528 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002529 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002530 if (rx > 0 && ry > 0) {
2531 if (paint.canComputeFastBounds()) {
2532 SkRect storage;
reed@google.com3b3e8952012-08-16 20:53:31 +00002533 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002534 return;
2535 }
2536 }
reed@google.com4ed0fb72012-12-12 20:48:18 +00002537 SkRRect rrect;
2538 rrect.setRectXY(r, rx, ry);
2539 this->drawRRect(rrect, paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002540 } else {
2541 this->drawRect(r, paint);
2542 }
2543}
2544
reed@android.com8a1c16f2008-12-17 15:59:43 +00002545void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2546 SkScalar sweepAngle, bool useCenter,
2547 const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002548 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002549 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2550 this->drawOval(oval, paint);
2551 } else {
2552 SkPath path;
2553 if (useCenter) {
2554 path.moveTo(oval.centerX(), oval.centerY());
2555 }
2556 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2557 if (useCenter) {
2558 path.close();
2559 }
2560 this->drawPath(path, paint);
2561 }
2562}
2563
2564void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2565 const SkPath& path, SkScalar hOffset,
2566 SkScalar vOffset, const SkPaint& paint) {
danakj9881d632014-11-26 12:41:06 -08002567 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
reed@android.com8a1c16f2008-12-17 15:59:43 +00002568 SkMatrix matrix;
reed@google.com4b226022011-01-11 18:32:13 +00002569
reed@android.com8a1c16f2008-12-17 15:59:43 +00002570 matrix.setTranslate(hOffset, vOffset);
2571 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2572}
2573
reed@android.comf76bacf2009-05-13 14:00:33 +00002574///////////////////////////////////////////////////////////////////////////////
reed1c2c4412015-04-30 13:09:24 -07002575
2576/**
2577 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2578 * against the playback cost of recursing into the subpicture to get at its actual ops.
2579 *
2580 * For now we pick a conservatively small value, though measurement (and other heuristics like
2581 * the type of ops contained) may justify changing this value.
2582 */
2583#define kMaxPictureOpsToUnrollInsteadOfRef 1
robertphillips9b14f262014-06-04 05:40:44 -07002584
reedd5fa1a42014-08-09 11:08:05 -07002585void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
reed1c2c4412015-04-30 13:09:24 -07002586 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
bsalomon49f085d2014-09-05 13:34:00 -07002587 if (picture) {
reedd5fa1a42014-08-09 11:08:05 -07002588 if (matrix && matrix->isIdentity()) {
2589 matrix = NULL;
2590 }
reed1c2c4412015-04-30 13:09:24 -07002591 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2592 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2593 picture->playback(this);
2594 } else {
2595 this->onDrawPicture(picture, matrix, paint);
2596 }
reedd5fa1a42014-08-09 11:08:05 -07002597 }
2598}
robertphillips9b14f262014-06-04 05:40:44 -07002599
reedd5fa1a42014-08-09 11:08:05 -07002600void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2601 const SkPaint* paint) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002602 SkBaseDevice* device = this->getTopDevice();
bsalomon49f085d2014-09-05 13:34:00 -07002603 if (device) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002604 // Canvas has to first give the device the opportunity to render
2605 // the picture itself.
reedd5fa1a42014-08-09 11:08:05 -07002606 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +00002607 return; // the device has rendered the entire picture
2608 }
2609 }
2610
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002611 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
robertphillipsc5ba71d2014-09-04 08:42:50 -07002612 picture->playback(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002613}
2614
reed@android.com8a1c16f2008-12-17 15:59:43 +00002615///////////////////////////////////////////////////////////////////////////////
2616///////////////////////////////////////////////////////////////////////////////
2617
2618SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
reed@google.comd6423292010-12-20 20:53:13 +00002619 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
reed@android.com8a1c16f2008-12-17 15:59:43 +00002620
2621 SkASSERT(canvas);
2622
2623 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2624 fDone = !fImpl->next();
2625}
2626
2627SkCanvas::LayerIter::~LayerIter() {
2628 fImpl->~SkDrawIter();
2629}
2630
2631void SkCanvas::LayerIter::next() {
2632 fDone = !fImpl->next();
2633}
2634
robertphillips@google.com1f2f3382013-08-29 11:54:56 +00002635SkBaseDevice* SkCanvas::LayerIter::device() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00002636 return fImpl->getDevice();
2637}
2638
2639const SkMatrix& SkCanvas::LayerIter::matrix() const {
2640 return fImpl->getMatrix();
2641}
2642
2643const SkPaint& SkCanvas::LayerIter::paint() const {
2644 const SkPaint* paint = fImpl->getPaint();
2645 if (NULL == paint) {
2646 paint = &fDefaultPaint;
2647 }
2648 return *paint;
2649}
2650
2651const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
2652int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
2653int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
justinlin@google.com20a550c2012-07-27 17:37:12 +00002654
2655///////////////////////////////////////////////////////////////////////////////
2656
fmalitac3b589a2014-06-05 12:40:07 -07002657SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002658
2659///////////////////////////////////////////////////////////////////////////////
2660
2661static bool supported_for_raster_canvas(const SkImageInfo& info) {
2662 switch (info.alphaType()) {
2663 case kPremul_SkAlphaType:
2664 case kOpaque_SkAlphaType:
2665 break;
2666 default:
2667 return false;
2668 }
2669
2670 switch (info.colorType()) {
2671 case kAlpha_8_SkColorType:
2672 case kRGB_565_SkColorType:
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +00002673 case kN32_SkColorType:
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +00002674 break;
2675 default:
2676 return false;
2677 }
2678
2679 return true;
2680}
2681
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002682SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2683 if (!supported_for_raster_canvas(info)) {
2684 return NULL;
2685 }
skia.committer@gmail.comeb849e52014-03-17 03:02:17 +00002686
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002687 SkBitmap bitmap;
2688 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2689 return NULL;
2690 }
commit-bot@chromium.org42b08932014-03-17 02:13:07 +00002691 return SkNEW_ARGS(SkCanvas, (bitmap));
2692}
reedd5fa1a42014-08-09 11:08:05 -07002693
2694///////////////////////////////////////////////////////////////////////////////
2695
2696SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002697 const SkPaint* paint, const SkRect& bounds)
reedd5fa1a42014-08-09 11:08:05 -07002698 : fCanvas(canvas)
2699 , fSaveCount(canvas->getSaveCount())
2700{
bsalomon49f085d2014-09-05 13:34:00 -07002701 if (paint) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002702 SkRect newBounds = bounds;
reedd5fa1a42014-08-09 11:08:05 -07002703 if (matrix) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002704 matrix->mapRect(&newBounds);
reedd5fa1a42014-08-09 11:08:05 -07002705 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -07002706 canvas->saveLayer(&newBounds, paint);
bsalomon49f085d2014-09-05 13:34:00 -07002707 } else if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002708 canvas->save();
2709 }
mtklein6cfa73a2014-08-13 13:33:49 -07002710
bsalomon49f085d2014-09-05 13:34:00 -07002711 if (matrix) {
reedd5fa1a42014-08-09 11:08:05 -07002712 canvas->concat(*matrix);
2713 }
2714}
2715
2716SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
2717 fCanvas->restoreToCount(fSaveCount);
2718}