1 /*
2 * Copyright 2008 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkBitmapDevice.h"
9 #include "SkCanvas.h"
10 #include "SkCanvasPriv.h"
11 #include "SkClipStack.h"
12 #include "SkColorFilter.h"
13 #include "SkDevice.h"
14 #include "SkDraw.h"
15 #include "SkDrawable.h"
16 #include "SkDrawFilter.h"
17 #include "SkDrawLooper.h"
18 #include "SkErrorInternals.h"
19 #include "SkImage.h"
20 #include "SkImage_Base.h"
21 #include "SkMatrixUtils.h"
22 #include "SkMetaData.h"
23 #include "SkNinePatchIter.h"
24 #include "SkPaintPriv.h"
25 #include "SkPatchUtils.h"
26 #include "SkPicture.h"
27 #include "SkRasterClip.h"
28 #include "SkReadPixelsRec.h"
29 #include "SkRRect.h"
30 #include "SkSmallAllocator.h"
31 #include "SkSurface_Base.h"
32 #include "SkTextBlob.h"
33 #include "SkTextFormatParams.h"
34 #include "SkTLazy.h"
35 #include "SkTraceEvent.h"
36
37 #include <new>
38
39 #if SK_SUPPORT_GPU
40 #include "GrContext.h"
41 #include "GrRenderTarget.h"
42 #include "SkGr.h"
43 #endif
44
45 #define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0)
46
47 /*
48 * Return true if the drawing this rect would hit every pixels in the canvas.
49 *
50 * Returns false if
51 * - rect does not contain the canvas' bounds
52 * - paint is not fill
53 * - paint would blur or otherwise change the coverage of the rect
54 */
wouldOverwriteEntireSurface(const SkRect * rect,const SkPaint * paint,ShaderOverrideOpacity overrideOpacity) const55 bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* paint,
56 ShaderOverrideOpacity overrideOpacity) const {
57 static_assert((int)SkPaintPriv::kNone_ShaderOverrideOpacity ==
58 (int)kNone_ShaderOverrideOpacity,
59 "need_matching_enums0");
60 static_assert((int)SkPaintPriv::kOpaque_ShaderOverrideOpacity ==
61 (int)kOpaque_ShaderOverrideOpacity,
62 "need_matching_enums1");
63 static_assert((int)SkPaintPriv::kNotOpaque_ShaderOverrideOpacity ==
64 (int)kNotOpaque_ShaderOverrideOpacity,
65 "need_matching_enums2");
66
67 const SkISize size = this->getBaseLayerSize();
68 const SkRect bounds = SkRect::MakeIWH(size.width(), size.height());
69 if (!this->getClipStack()->quickContains(bounds)) {
70 return false;
71 }
72
73 if (rect) {
74 if (!this->getTotalMatrix().rectStaysRect()) {
75 return false; // conservative
76 }
77
78 SkRect devRect;
79 this->getTotalMatrix().mapRect(&devRect, *rect);
80 if (!devRect.contains(bounds)) {
81 return false;
82 }
83 }
84
85 if (paint) {
86 SkPaint::Style paintStyle = paint->getStyle();
87 if (!(paintStyle == SkPaint::kFill_Style ||
88 paintStyle == SkPaint::kStrokeAndFill_Style)) {
89 return false;
90 }
91 if (paint->getMaskFilter() || paint->getLooper()
92 || paint->getPathEffect() || paint->getImageFilter()) {
93 return false; // conservative
94 }
95 }
96 return SkPaintPriv::Overwrites(paint, (SkPaintPriv::ShaderOverrideOpacity)overrideOpacity);
97 }
98
99 ///////////////////////////////////////////////////////////////////////////////////////////////////
100
101 static bool gIgnoreSaveLayerBounds;
Internal_Private_SetIgnoreSaveLayerBounds(bool ignore)102 void SkCanvas::Internal_Private_SetIgnoreSaveLayerBounds(bool ignore) {
103 gIgnoreSaveLayerBounds = ignore;
104 }
Internal_Private_GetIgnoreSaveLayerBounds()105 bool SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds() {
106 return gIgnoreSaveLayerBounds;
107 }
108
109 static bool gTreatSpriteAsBitmap;
Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap)110 void SkCanvas::Internal_Private_SetTreatSpriteAsBitmap(bool spriteAsBitmap) {
111 gTreatSpriteAsBitmap = spriteAsBitmap;
112 }
Internal_Private_GetTreatSpriteAsBitmap()113 bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() {
114 return gTreatSpriteAsBitmap;
115 }
116
117 // experimental for faster tiled drawing...
118 //#define SK_ENABLE_CLIP_QUICKREJECT
119 //#define SK_TRACE_SAVERESTORE
120
121 #ifdef SK_TRACE_SAVERESTORE
122 static int gLayerCounter;
inc_layer()123 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
dec_layer()124 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
125
126 static int gRecCounter;
inc_rec()127 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
dec_rec()128 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
129
130 static int gCanvasCounter;
inc_canvas()131 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
dec_canvas()132 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
133 #else
134 #define inc_layer()
135 #define dec_layer()
136 #define inc_rec()
137 #define dec_rec()
138 #define inc_canvas()
139 #define dec_canvas()
140 #endif
141
142 typedef SkTLazy<SkPaint> SkLazyPaint;
143
predrawNotify(bool willOverwritesEntireSurface)144 void SkCanvas::predrawNotify(bool willOverwritesEntireSurface) {
145 if (fSurfaceBase) {
146 fSurfaceBase->aboutToDraw(willOverwritesEntireSurface
147 ? SkSurface::kDiscard_ContentChangeMode
148 : SkSurface::kRetain_ContentChangeMode);
149 }
150 }
151
predrawNotify(const SkRect * rect,const SkPaint * paint,ShaderOverrideOpacity overrideOpacity)152 void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint,
153 ShaderOverrideOpacity overrideOpacity) {
154 if (fSurfaceBase) {
155 SkSurface::ContentChangeMode mode = SkSurface::kRetain_ContentChangeMode;
156 // Since willOverwriteAllPixels() may not be complete free to call, we only do so if
157 // there is an outstanding snapshot, since w/o that, there will be no copy-on-write
158 // and therefore we don't care which mode we're in.
159 //
160 if (fSurfaceBase->outstandingImageSnapshot()) {
161 if (this->wouldOverwriteEntireSurface(rect, paint, overrideOpacity)) {
162 mode = SkSurface::kDiscard_ContentChangeMode;
163 }
164 }
165 fSurfaceBase->aboutToDraw(mode);
166 }
167 }
168
169 ///////////////////////////////////////////////////////////////////////////////
170
filter_paint_flags(const SkSurfaceProps & props,uint32_t flags)171 static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) {
172 const uint32_t propFlags = props.flags();
173 if (propFlags & SkSurfaceProps::kDisallowDither_Flag) {
174 flags &= ~SkPaint::kDither_Flag;
175 }
176 if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) {
177 flags &= ~SkPaint::kAntiAlias_Flag;
178 }
179 return flags;
180 }
181
182 ///////////////////////////////////////////////////////////////////////////////
183
184 /* This is the record we keep for each SkBaseDevice that the user installs.
185 The clip/matrix/proc are fields that reflect the top of the save/restore
186 stack. Whenever the canvas changes, it marks a dirty flag, and then before
187 these are used (assuming we're not on a layer) we rebuild these cache
188 values: they reflect the top of the save stack, but translated and clipped
189 by the device's XY offset and bitmap-bounds.
190 */
191 struct DeviceCM {
192 DeviceCM* fNext;
193 SkBaseDevice* fDevice;
194 SkRasterClip fClip;
195 SkPaint* fPaint; // may be null (in the future)
196 const SkMatrix* fMatrix;
197 SkMatrix fMatrixStorage;
198 const bool fDeviceIsBitmapDevice;
199
DeviceCMDeviceCM200 DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
201 bool conservativeRasterClip, bool deviceIsBitmapDevice)
202 : fNext(nullptr)
203 , fClip(conservativeRasterClip)
204 , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
205 {
206 if (nullptr != device) {
207 device->ref();
208 device->onAttachToCanvas(canvas);
209 }
210 fDevice = device;
211 fPaint = paint ? new SkPaint(*paint) : nullptr;
212 }
213
~DeviceCMDeviceCM214 ~DeviceCM() {
215 if (fDevice) {
216 fDevice->onDetachFromCanvas();
217 fDevice->unref();
218 }
219 delete fPaint;
220 }
221
resetDeviceCM222 void reset(const SkIRect& bounds) {
223 SkASSERT(!fPaint);
224 SkASSERT(!fNext);
225 SkASSERT(fDevice);
226 fClip.setRect(bounds);
227 }
228
updateMCDeviceCM229 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
230 const SkClipStack& clipStack, SkRasterClip* updateClip) {
231 int x = fDevice->getOrigin().x();
232 int y = fDevice->getOrigin().y();
233 int width = fDevice->width();
234 int height = fDevice->height();
235
236 if ((x | y) == 0) {
237 fMatrix = &totalMatrix;
238 fClip = totalClip;
239 } else {
240 fMatrixStorage = totalMatrix;
241 fMatrixStorage.postTranslate(SkIntToScalar(-x),
242 SkIntToScalar(-y));
243 fMatrix = &fMatrixStorage;
244
245 totalClip.translate(-x, -y, &fClip);
246 }
247
248 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
249
250 // intersect clip, but don't translate it (yet)
251
252 if (updateClip) {
253 updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
254 SkRegion::kDifference_Op);
255 }
256
257 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
258
259 #ifdef SK_DEBUG
260 if (!fClip.isEmpty()) {
261 SkIRect deviceR;
262 deviceR.set(0, 0, width, height);
263 SkASSERT(deviceR.contains(fClip.getBounds()));
264 }
265 #endif
266 }
267 };
268
269 /* This is the record we keep for each save/restore level in the stack.
270 Since a level optionally copies the matrix and/or stack, we have pointers
271 for these fields. If the value is copied for this level, the copy is
272 stored in the ...Storage field, and the pointer points to that. If the
273 value is not copied for this level, we ignore ...Storage, and just point
274 at the corresponding value in the previous level in the stack.
275 */
276 class SkCanvas::MCRec {
277 public:
278 SkDrawFilter* fFilter; // the current filter (or null)
279 DeviceCM* fLayer;
280 /* If there are any layers in the stack, this points to the top-most
281 one that is at or below this level in the stack (so we know what
282 bitmap/device to draw into from this level. This value is NOT
283 reference counted, since the real owner is either our fLayer field,
284 or a previous one in a lower level.)
285 */
286 DeviceCM* fTopLayer;
287 SkRasterClip fRasterClip;
288 SkMatrix fMatrix;
289 int fDeferredSaveCount;
290
MCRec(bool conservativeRasterClip)291 MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
292 fFilter = nullptr;
293 fLayer = nullptr;
294 fTopLayer = nullptr;
295 fMatrix.reset();
296 fDeferredSaveCount = 0;
297
298 // don't bother initializing fNext
299 inc_rec();
300 }
MCRec(const MCRec & prev)301 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) {
302 fFilter = SkSafeRef(prev.fFilter);
303 fLayer = nullptr;
304 fTopLayer = prev.fTopLayer;
305 fDeferredSaveCount = 0;
306
307 // don't bother initializing fNext
308 inc_rec();
309 }
~MCRec()310 ~MCRec() {
311 SkSafeUnref(fFilter);
312 delete fLayer;
313 dec_rec();
314 }
315
reset(const SkIRect & bounds)316 void reset(const SkIRect& bounds) {
317 SkASSERT(fLayer);
318 SkASSERT(fDeferredSaveCount == 0);
319
320 fMatrix.reset();
321 fRasterClip.setRect(bounds);
322 fLayer->reset(bounds);
323 }
324 };
325
326 class SkDrawIter : public SkDraw {
327 public:
SkDrawIter(SkCanvas * canvas,bool skipEmptyClips=true)328 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
329 canvas = canvas->canvasForDrawIter();
330 fCanvas = canvas;
331 canvas->updateDeviceCMCache();
332
333 fClipStack = canvas->fClipStack;
334 fCurrLayer = canvas->fMCRec->fTopLayer;
335 fSkipEmptyClips = skipEmptyClips;
336 }
337
next()338 bool next() {
339 // skip over recs with empty clips
340 if (fSkipEmptyClips) {
341 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
342 fCurrLayer = fCurrLayer->fNext;
343 }
344 }
345
346 const DeviceCM* rec = fCurrLayer;
347 if (rec && rec->fDevice) {
348
349 fMatrix = rec->fMatrix;
350 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
351 fRC = &rec->fClip;
352 fDevice = rec->fDevice;
353 if (!fDevice->accessPixels(&fDst)) {
354 fDst.reset(fDevice->imageInfo(), nullptr, 0);
355 }
356 fPaint = rec->fPaint;
357 SkDEBUGCODE(this->validate();)
358
359 fCurrLayer = rec->fNext;
360 // fCurrLayer may be nullptr now
361
362 return true;
363 }
364 return false;
365 }
366
getDevice() const367 SkBaseDevice* getDevice() const { return fDevice; }
getX() const368 int getX() const { return fDevice->getOrigin().x(); }
getY() const369 int getY() const { return fDevice->getOrigin().y(); }
getMatrix() const370 const SkMatrix& getMatrix() const { return *fMatrix; }
getClip() const371 const SkRegion& getClip() const { return *fClip; }
getPaint() const372 const SkPaint* getPaint() const { return fPaint; }
373
374 private:
375 SkCanvas* fCanvas;
376 const DeviceCM* fCurrLayer;
377 const SkPaint* fPaint; // May be null.
378 SkBool8 fSkipEmptyClips;
379
380 typedef SkDraw INHERITED;
381 };
382
383 /////////////////////////////////////////////////////////////////////////////
384
set_if_needed(SkLazyPaint * lazy,const SkPaint & orig)385 static SkPaint* set_if_needed(SkLazyPaint* lazy, const SkPaint& orig) {
386 return lazy->isValid() ? lazy->get() : lazy->set(orig);
387 }
388
389 /**
390 * If the paint has an imagefilter, but it can be simplified to just a colorfilter, return that
391 * colorfilter, else return nullptr.
392 */
image_to_color_filter(const SkPaint & paint)393 static SkColorFilter* image_to_color_filter(const SkPaint& paint) {
394 SkImageFilter* imgf = paint.getImageFilter();
395 if (!imgf) {
396 return nullptr;
397 }
398
399 SkColorFilter* imgCF;
400 if (!imgf->asAColorFilter(&imgCF)) {
401 return nullptr;
402 }
403
404 SkColorFilter* paintCF = paint.getColorFilter();
405 if (nullptr == paintCF) {
406 // there is no existing paint colorfilter, so we can just return the imagefilter's
407 return imgCF;
408 }
409
410 // The paint has both a colorfilter(paintCF) and an imagefilter-which-is-a-colorfilter(imgCF)
411 // and we need to combine them into a single colorfilter.
412 SkAutoTUnref<SkColorFilter> autoImgCF(imgCF);
413 return SkColorFilter::CreateComposeFilter(imgCF, paintCF);
414 }
415
416 /**
417 * There are many bounds in skia. A circle's bounds is just its center extended by its radius.
418 * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw
419 * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional
420 * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters,
421 * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the
422 * conservative "effective" bounds based on the settings in the paint... with one exception. This
423 * function does *not* look at the imagefilter, which can also modify the effective bounds. It is
424 * deliberately ignored.
425 */
apply_paint_to_bounds_sans_imagefilter(const SkPaint & paint,const SkRect & rawBounds,SkRect * storage)426 static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint,
427 const SkRect& rawBounds,
428 SkRect* storage) {
429 SkPaint tmpUnfiltered(paint);
430 tmpUnfiltered.setImageFilter(nullptr);
431 if (tmpUnfiltered.canComputeFastBounds()) {
432 return tmpUnfiltered.computeFastBounds(rawBounds, storage);
433 } else {
434 return rawBounds;
435 }
436 }
437
438 class AutoDrawLooper {
439 public:
440 // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
441 // paint. It's used to determine the size of the offscreen layer for filters.
442 // If null, the clip will be used instead.
AutoDrawLooper(SkCanvas * canvas,const SkSurfaceProps & props,const SkPaint & paint,bool skipLayerForImageFilter=false,const SkRect * rawBounds=nullptr)443 AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
444 bool skipLayerForImageFilter = false,
445 const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
446 fCanvas = canvas;
447 #ifdef SK_SUPPORT_LEGACY_DRAWFILTER
448 fFilter = canvas->getDrawFilter();
449 #else
450 fFilter = nullptr;
451 #endif
452 fPaint = &fOrigPaint;
453 fSaveCount = canvas->getSaveCount();
454 fTempLayerForImageFilter = false;
455 fDone = false;
456
457 SkColorFilter* simplifiedCF = image_to_color_filter(fOrigPaint);
458 if (simplifiedCF) {
459 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
460 paint->setColorFilter(simplifiedCF)->unref();
461 paint->setImageFilter(nullptr);
462 fPaint = paint;
463 }
464
465 if (!skipLayerForImageFilter && fPaint->getImageFilter()) {
466 /**
467 * We implement ImageFilters for a given draw by creating a layer, then applying the
468 * imagefilter to the pixels of that layer (its backing surface/image), and then
469 * we call restore() to xfer that layer to the main canvas.
470 *
471 * 1. SaveLayer (with a paint containing the current imagefilter and xfermode)
472 * 2. Generate the src pixels:
473 * Remove the imagefilter and the xfermode from the paint that we (AutoDrawLooper)
474 * return (fPaint). We then draw the primitive (using srcover) into a cleared
475 * buffer/surface.
476 * 3. Restore the layer created in #1
477 * The imagefilter is passed the buffer/surface from the layer (now filled with the
478 * src pixels of the primitive). It returns a new "filtered" buffer, which we
479 * draw onto the previous layer using the xfermode from the original paint.
480 */
481 SkPaint tmp;
482 tmp.setImageFilter(fPaint->getImageFilter());
483 tmp.setXfermode(fPaint->getXfermode());
484 SkRect storage;
485 if (rawBounds) {
486 // Make rawBounds include all paint outsets except for those due to image filters.
487 rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage);
488 }
489 (void)canvas->internalSaveLayer(SkCanvas::SaveLayerRec(rawBounds, &tmp),
490 SkCanvas::kFullLayer_SaveLayerStrategy);
491 fTempLayerForImageFilter = true;
492 // we remove the imagefilter/xfermode inside doNext()
493 }
494
495 if (SkDrawLooper* looper = paint.getLooper()) {
496 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
497 looper->contextSize());
498 fLooperContext = looper->createContext(canvas, buffer);
499 fIsSimple = false;
500 } else {
501 fLooperContext = nullptr;
502 // can we be marked as simple?
503 fIsSimple = !fFilter && !fTempLayerForImageFilter;
504 }
505
506 uint32_t oldFlags = paint.getFlags();
507 fNewPaintFlags = filter_paint_flags(props, oldFlags);
508 if (fIsSimple && (fNewPaintFlags != oldFlags)) {
509 SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint);
510 paint->setFlags(fNewPaintFlags);
511 fPaint = paint;
512 // if we're not simple, doNext() will take care of calling setFlags()
513 }
514 }
515
~AutoDrawLooper()516 ~AutoDrawLooper() {
517 if (fTempLayerForImageFilter) {
518 fCanvas->internalRestore();
519 }
520 SkASSERT(fCanvas->getSaveCount() == fSaveCount);
521 }
522
paint() const523 const SkPaint& paint() const {
524 SkASSERT(fPaint);
525 return *fPaint;
526 }
527
next(SkDrawFilter::Type drawType)528 bool next(SkDrawFilter::Type drawType) {
529 if (fDone) {
530 return false;
531 } else if (fIsSimple) {
532 fDone = true;
533 return !fPaint->nothingToDraw();
534 } else {
535 return this->doNext(drawType);
536 }
537 }
538
539 private:
540 SkLazyPaint fLazyPaintInit; // base paint storage in case we need to modify it
541 SkLazyPaint fLazyPaintPerLooper; // per-draw-looper storage, so the looper can modify it
542 SkCanvas* fCanvas;
543 const SkPaint& fOrigPaint;
544 SkDrawFilter* fFilter;
545 const SkPaint* fPaint;
546 int fSaveCount;
547 uint32_t fNewPaintFlags;
548 bool fTempLayerForImageFilter;
549 bool fDone;
550 bool fIsSimple;
551 SkDrawLooper::Context* fLooperContext;
552 SkSmallAllocator<1, 32> fLooperContextAllocator;
553
554 bool doNext(SkDrawFilter::Type drawType);
555 };
556
doNext(SkDrawFilter::Type drawType)557 bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
558 fPaint = nullptr;
559 SkASSERT(!fIsSimple);
560 SkASSERT(fLooperContext || fFilter || fTempLayerForImageFilter);
561
562 SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ?
563 *fLazyPaintInit.get() : fOrigPaint);
564 paint->setFlags(fNewPaintFlags);
565
566 if (fTempLayerForImageFilter) {
567 paint->setImageFilter(nullptr);
568 paint->setXfermode(nullptr);
569 }
570
571 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
572 fDone = true;
573 return false;
574 }
575 if (fFilter) {
576 if (!fFilter->filter(paint, drawType)) {
577 fDone = true;
578 return false;
579 }
580 if (nullptr == fLooperContext) {
581 // no looper means we only draw once
582 fDone = true;
583 }
584 }
585 fPaint = paint;
586
587 // if we only came in here for the imagefilter, mark us as done
588 if (!fLooperContext && !fFilter) {
589 fDone = true;
590 }
591
592 // call this after any possible paint modifiers
593 if (fPaint->nothingToDraw()) {
594 fPaint = nullptr;
595 return false;
596 }
597 return true;
598 }
599
600 ////////// macros to place around the internal draw calls //////////////////
601
602 #define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
603 this->predrawNotify(); \
604 AutoDrawLooper looper(this, fProps, paint, skipLayerForFilter, bounds); \
605 while (looper.next(SkDrawFilter::kBitmap_Type)) { \
606 SkDrawIter iter(this);
607
608
609 #define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
610 this->predrawNotify(); \
611 AutoDrawLooper looper(this, fProps, paint, true); \
612 while (looper.next(type)) { \
613 SkDrawIter iter(this);
614
615 #define LOOPER_BEGIN(paint, type, bounds) \
616 this->predrawNotify(); \
617 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
618 while (looper.next(type)) { \
619 SkDrawIter iter(this);
620
621 #define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
622 this->predrawNotify(bounds, &paint, auxOpaque); \
623 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
624 while (looper.next(type)) { \
625 SkDrawIter iter(this);
626
627 #define LOOPER_END }
628
629 ////////////////////////////////////////////////////////////////////////////
630
resetForNextPicture(const SkIRect & bounds)631 void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
632 this->restoreToCount(1);
633 fCachedLocalClipBounds.setEmpty();
634 fCachedLocalClipBoundsDirty = true;
635 fClipStack->reset();
636 fMCRec->reset(bounds);
637
638 // We're peering through a lot of structs here. Only at this scope do we
639 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
640 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
641 }
642
init(SkBaseDevice * device,InitFlags flags)643 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
644 if (device && device->forceConservativeRasterClip()) {
645 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
646 }
647 // Since init() is only called once by our constructors, it is safe to perform this
648 // const-cast.
649 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
650
651 fCachedLocalClipBounds.setEmpty();
652 fCachedLocalClipBoundsDirty = true;
653 fAllowSoftClip = true;
654 fAllowSimplifyClip = false;
655 fDeviceCMDirty = true;
656 fSaveCount = 1;
657 fMetaData = nullptr;
658
659 fClipStack.reset(new SkClipStack);
660
661 fMCRec = (MCRec*)fMCStack.push_back();
662 new (fMCRec) MCRec(fConservativeRasterClip);
663
664 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
665 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
666 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, false);
667
668 fMCRec->fTopLayer = fMCRec->fLayer;
669
670 fSurfaceBase = nullptr;
671
672 if (device) {
673 // The root device and the canvas should always have the same pixel geometry
674 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
675 device->onAttachToCanvas(this);
676 fMCRec->fLayer->fDevice = SkRef(device);
677 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
678 }
679 return device;
680 }
681
SkCanvas()682 SkCanvas::SkCanvas()
683 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
684 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
685 , fConservativeRasterClip(false)
686 {
687 inc_canvas();
688
689 this->init(nullptr, kDefault_InitFlags);
690 }
691
make_nopixels(int width,int height)692 static SkBitmap make_nopixels(int width, int height) {
693 SkBitmap bitmap;
694 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
695 return bitmap;
696 }
697
698 class SkNoPixelsBitmapDevice : public SkBitmapDevice {
699 public:
SkNoPixelsBitmapDevice(const SkIRect & bounds,const SkSurfaceProps & surfaceProps)700 SkNoPixelsBitmapDevice(const SkIRect& bounds, const SkSurfaceProps& surfaceProps)
701 : INHERITED(make_nopixels(bounds.width(), bounds.height()), surfaceProps)
702 {
703 this->setOrigin(bounds.x(), bounds.y());
704 }
705
706 private:
707
708 typedef SkBitmapDevice INHERITED;
709 };
710
SkCanvas(int width,int height,const SkSurfaceProps * props)711 SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
712 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
713 , fProps(SkSurfacePropsCopyOrDefault(props))
714 , fConservativeRasterClip(false)
715 {
716 inc_canvas();
717
718 this->init(new SkNoPixelsBitmapDevice(SkIRect::MakeWH(width, height), fProps),
719 kDefault_InitFlags)->unref();
720 }
721
SkCanvas(const SkIRect & bounds,InitFlags flags)722 SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
723 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
724 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
725 , fConservativeRasterClip(false)
726 {
727 inc_canvas();
728
729 this->init(new SkNoPixelsBitmapDevice(bounds, fProps), flags)->unref();
730 }
731
SkCanvas(SkBaseDevice * device)732 SkCanvas::SkCanvas(SkBaseDevice* device)
733 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
734 , fProps(device->surfaceProps())
735 , fConservativeRasterClip(false)
736 {
737 inc_canvas();
738
739 this->init(device, kDefault_InitFlags);
740 }
741
SkCanvas(SkBaseDevice * device,InitFlags flags)742 SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
743 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
744 , fProps(device->surfaceProps())
745 , fConservativeRasterClip(false)
746 {
747 inc_canvas();
748
749 this->init(device, flags);
750 }
751
SkCanvas(const SkBitmap & bitmap,const SkSurfaceProps & props)752 SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
753 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
754 , fProps(props)
755 , fConservativeRasterClip(false)
756 {
757 inc_canvas();
758
759 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
760 this->init(device, kDefault_InitFlags);
761 }
762
SkCanvas(const SkBitmap & bitmap)763 SkCanvas::SkCanvas(const SkBitmap& bitmap)
764 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
765 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
766 , fConservativeRasterClip(false)
767 {
768 inc_canvas();
769
770 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
771 this->init(device, kDefault_InitFlags);
772 }
773
~SkCanvas()774 SkCanvas::~SkCanvas() {
775 // free up the contents of our deque
776 this->restoreToCount(1); // restore everything but the last
777
778 this->internalRestore(); // restore the last, since we're going away
779
780 delete fMetaData;
781
782 dec_canvas();
783 }
784
785 #ifdef SK_SUPPORT_LEGACY_DRAWFILTER
getDrawFilter() const786 SkDrawFilter* SkCanvas::getDrawFilter() const {
787 return fMCRec->fFilter;
788 }
789
setDrawFilter(SkDrawFilter * filter)790 SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
791 this->checkForDeferredSave();
792 SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
793 return filter;
794 }
795 #endif
796
getMetaData()797 SkMetaData& SkCanvas::getMetaData() {
798 // metadata users are rare, so we lazily allocate it. If that changes we
799 // can decide to just make it a field in the device (rather than a ptr)
800 if (nullptr == fMetaData) {
801 fMetaData = new SkMetaData;
802 }
803 return *fMetaData;
804 }
805
806 ///////////////////////////////////////////////////////////////////////////////
807
flush()808 void SkCanvas::flush() {
809 SkBaseDevice* device = this->getDevice();
810 if (device) {
811 device->flush();
812 }
813 }
814
getBaseLayerSize() const815 SkISize SkCanvas::getBaseLayerSize() const {
816 SkBaseDevice* d = this->getDevice();
817 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
818 }
819
getTopLayerBounds() const820 SkIRect SkCanvas::getTopLayerBounds() const {
821 SkBaseDevice* d = this->getTopDevice();
822 if (!d) {
823 return SkIRect::MakeEmpty();
824 }
825 return SkIRect::MakeXYWH(d->getOrigin().x(), d->getOrigin().y(), d->width(), d->height());
826 }
827
getDevice() const828 SkBaseDevice* SkCanvas::getDevice() const {
829 // return root device
830 MCRec* rec = (MCRec*) fMCStack.front();
831 SkASSERT(rec && rec->fLayer);
832 return rec->fLayer->fDevice;
833 }
834
getTopDevice(bool updateMatrixClip) const835 SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const {
836 if (updateMatrixClip) {
837 const_cast<SkCanvas*>(this)->updateDeviceCMCache();
838 }
839 return fMCRec->fTopLayer->fDevice;
840 }
841
readPixels(SkBitmap * bitmap,int x,int y)842 bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
843 if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
844 return false;
845 }
846
847 bool weAllocated = false;
848 if (nullptr == bitmap->pixelRef()) {
849 if (!bitmap->tryAllocPixels()) {
850 return false;
851 }
852 weAllocated = true;
853 }
854
855 SkAutoPixmapUnlock unlocker;
856 if (bitmap->requestLock(&unlocker)) {
857 const SkPixmap& pm = unlocker.pixmap();
858 if (this->readPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), x, y)) {
859 return true;
860 }
861 }
862
863 if (weAllocated) {
864 bitmap->setPixelRef(nullptr);
865 }
866 return false;
867 }
868
readPixels(const SkIRect & srcRect,SkBitmap * bitmap)869 bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
870 SkIRect r = srcRect;
871 const SkISize size = this->getBaseLayerSize();
872 if (!r.intersect(0, 0, size.width(), size.height())) {
873 bitmap->reset();
874 return false;
875 }
876
877 if (!bitmap->tryAllocN32Pixels(r.width(), r.height())) {
878 // bitmap will already be reset.
879 return false;
880 }
881 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
882 bitmap->reset();
883 return false;
884 }
885 return true;
886 }
887
readPixels(const SkImageInfo & dstInfo,void * dstP,size_t rowBytes,int x,int y)888 bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowBytes, int x, int y) {
889 SkBaseDevice* device = this->getDevice();
890 if (!device) {
891 return false;
892 }
893 const SkISize size = this->getBaseLayerSize();
894
895 SkReadPixelsRec rec(dstInfo, dstP, rowBytes, x, y);
896 if (!rec.trim(size.width(), size.height())) {
897 return false;
898 }
899
900 // The device can assert that the requested area is always contained in its bounds
901 return device->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY);
902 }
903
writePixels(const SkBitmap & bitmap,int x,int y)904 bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
905 if (bitmap.getTexture()) {
906 return false;
907 }
908
909 SkAutoPixmapUnlock unlocker;
910 if (bitmap.requestLock(&unlocker)) {
911 const SkPixmap& pm = unlocker.pixmap();
912 return this->writePixels(pm.info(), pm.addr(), pm.rowBytes(), x, y);
913 }
914 return false;
915 }
916
writePixels(const SkImageInfo & origInfo,const void * pixels,size_t rowBytes,int x,int y)917 bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
918 int x, int y) {
919 switch (origInfo.colorType()) {
920 case kUnknown_SkColorType:
921 case kIndex_8_SkColorType:
922 return false;
923 default:
924 break;
925 }
926 if (nullptr == pixels || rowBytes < origInfo.minRowBytes()) {
927 return false;
928 }
929
930 const SkISize size = this->getBaseLayerSize();
931 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
932 if (!target.intersect(0, 0, size.width(), size.height())) {
933 return false;
934 }
935
936 SkBaseDevice* device = this->getDevice();
937 if (!device) {
938 return false;
939 }
940
941 // the intersect may have shrunk info's logical size
942 const SkImageInfo info = origInfo.makeWH(target.width(), target.height());
943
944 // if x or y are negative, then we have to adjust pixels
945 if (x > 0) {
946 x = 0;
947 }
948 if (y > 0) {
949 y = 0;
950 }
951 // here x,y are either 0 or negative
952 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
953
954 // Tell our owning surface to bump its generation ID
955 const bool completeOverwrite = info.dimensions() == size;
956 this->predrawNotify(completeOverwrite);
957
958 // The device can assert that the requested area is always contained in its bounds
959 return device->writePixels(info, pixels, rowBytes, target.x(), target.y());
960 }
961
canvasForDrawIter()962 SkCanvas* SkCanvas::canvasForDrawIter() {
963 return this;
964 }
965
966 //////////////////////////////////////////////////////////////////////////////
967
updateDeviceCMCache()968 void SkCanvas::updateDeviceCMCache() {
969 if (fDeviceCMDirty) {
970 const SkMatrix& totalMatrix = this->getTotalMatrix();
971 const SkRasterClip& totalClip = fMCRec->fRasterClip;
972 DeviceCM* layer = fMCRec->fTopLayer;
973
974 if (nullptr == layer->fNext) { // only one layer
975 layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr);
976 } else {
977 SkRasterClip clip(totalClip);
978 do {
979 layer->updateMC(totalMatrix, clip, *fClipStack, &clip);
980 } while ((layer = layer->fNext) != nullptr);
981 }
982 fDeviceCMDirty = false;
983 }
984 }
985
986 ///////////////////////////////////////////////////////////////////////////////
987
checkForDeferredSave()988 void SkCanvas::checkForDeferredSave() {
989 if (fMCRec->fDeferredSaveCount > 0) {
990 this->doSave();
991 }
992 }
993
getSaveCount() const994 int SkCanvas::getSaveCount() const {
995 #ifdef SK_DEBUG
996 int count = 0;
997 SkDeque::Iter iter(fMCStack, SkDeque::Iter::kFront_IterStart);
998 for (;;) {
999 const MCRec* rec = (const MCRec*)iter.next();
1000 if (!rec) {
1001 break;
1002 }
1003 count += 1 + rec->fDeferredSaveCount;
1004 }
1005 SkASSERT(count == fSaveCount);
1006 #endif
1007 return fSaveCount;
1008 }
1009
save()1010 int SkCanvas::save() {
1011 fSaveCount += 1;
1012 fMCRec->fDeferredSaveCount += 1;
1013 return this->getSaveCount() - 1; // return our prev value
1014 }
1015
doSave()1016 void SkCanvas::doSave() {
1017 this->willSave();
1018
1019 SkASSERT(fMCRec->fDeferredSaveCount > 0);
1020 fMCRec->fDeferredSaveCount -= 1;
1021 this->internalSave();
1022 }
1023
restore()1024 void SkCanvas::restore() {
1025 if (fMCRec->fDeferredSaveCount > 0) {
1026 SkASSERT(fSaveCount > 1);
1027 fSaveCount -= 1;
1028 fMCRec->fDeferredSaveCount -= 1;
1029 } else {
1030 // check for underflow
1031 if (fMCStack.count() > 1) {
1032 this->willRestore();
1033 SkASSERT(fSaveCount > 1);
1034 fSaveCount -= 1;
1035 this->internalRestore();
1036 this->didRestore();
1037 }
1038 }
1039 }
1040
restoreToCount(int count)1041 void SkCanvas::restoreToCount(int count) {
1042 // sanity check
1043 if (count < 1) {
1044 count = 1;
1045 }
1046
1047 int n = this->getSaveCount() - count;
1048 for (int i = 0; i < n; ++i) {
1049 this->restore();
1050 }
1051 }
1052
internalSave()1053 void SkCanvas::internalSave() {
1054 MCRec* newTop = (MCRec*)fMCStack.push_back();
1055 new (newTop) MCRec(*fMCRec); // balanced in restore()
1056 fMCRec = newTop;
1057
1058 fClipStack->save();
1059 }
1060
BoundsAffectsClip(SaveLayerFlags saveLayerFlags)1061 bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) {
1062 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
1063 return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag);
1064 #else
1065 return true;
1066 #endif
1067 }
1068
clipRectBounds(const SkRect * bounds,SaveLayerFlags saveLayerFlags,SkIRect * intersection,const SkImageFilter * imageFilter)1069 bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags,
1070 SkIRect* intersection, const SkImageFilter* imageFilter) {
1071 SkIRect clipBounds;
1072 if (!this->getClipDeviceBounds(&clipBounds)) {
1073 return false;
1074 }
1075
1076 const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix()
1077
1078 if (imageFilter) {
1079 imageFilter->filterBounds(clipBounds, ctm, &clipBounds);
1080 if (bounds && !imageFilter->canComputeFastBounds()) {
1081 bounds = nullptr;
1082 }
1083 }
1084 SkIRect ir;
1085 if (bounds) {
1086 SkRect r;
1087
1088 ctm.mapRect(&r, *bounds);
1089 r.roundOut(&ir);
1090 // early exit if the layer's bounds are clipped out
1091 if (!ir.intersect(clipBounds)) {
1092 if (BoundsAffectsClip(saveLayerFlags)) {
1093 fCachedLocalClipBoundsDirty = true;
1094 fMCRec->fRasterClip.setEmpty();
1095 }
1096 return false;
1097 }
1098 } else { // no user bounds, so just use the clip
1099 ir = clipBounds;
1100 }
1101 SkASSERT(!ir.isEmpty());
1102
1103 if (BoundsAffectsClip(saveLayerFlags)) {
1104 // Simplify the current clips since they will be applied properly during restore()
1105 fCachedLocalClipBoundsDirty = true;
1106 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
1107 fMCRec->fRasterClip.setRect(ir);
1108 }
1109
1110 if (intersection) {
1111 *intersection = ir;
1112 }
1113 return true;
1114 }
1115
1116
saveLayer(const SkRect * bounds,const SkPaint * paint)1117 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
1118 return this->saveLayer(SaveLayerRec(bounds, paint, 0));
1119 }
1120
saveLayerPreserveLCDTextRequests(const SkRect * bounds,const SkPaint * paint)1121 int SkCanvas::saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint) {
1122 return this->saveLayer(SaveLayerRec(bounds, paint, kPreserveLCDText_SaveLayerFlag));
1123 }
1124
saveLayer(const SaveLayerRec & origRec)1125 int SkCanvas::saveLayer(const SaveLayerRec& origRec) {
1126 SaveLayerRec rec(origRec);
1127 if (gIgnoreSaveLayerBounds) {
1128 rec.fBounds = nullptr;
1129 }
1130 SaveLayerStrategy strategy = this->getSaveLayerStrategy(rec);
1131 fSaveCount += 1;
1132 this->internalSaveLayer(rec, strategy);
1133 return this->getSaveCount() - 1;
1134 }
1135
draw_filter_into_device(SkBaseDevice * src,const SkImageFilter * filter,SkBaseDevice * dst,const SkMatrix & ctm)1136 static void draw_filter_into_device(SkBaseDevice* src, const SkImageFilter* filter,
1137 SkBaseDevice* dst, const SkMatrix& ctm) {
1138
1139 SkBitmap srcBM;
1140
1141 #if SK_SUPPORT_GPU
1142 GrRenderTarget* srcRT = src->accessRenderTarget();
1143 if (srcRT && !srcRT->asTexture() && dst->accessRenderTarget()) {
1144 // When both the src & the dst are on the gpu but the src doesn't have a texture,
1145 // we create a temporary texture for the draw.
1146 // TODO: we should actually only copy the portion of the source needed to apply the image
1147 // filter
1148 GrContext* context = srcRT->getContext();
1149 SkAutoTUnref<GrTexture> tex(context->textureProvider()->createTexture(srcRT->desc(),
1150 SkBudgeted::kYes));
1151
1152 context->copySurface(tex, srcRT);
1153
1154 GrWrapTextureInBitmap(tex, src->width(), src->height(), src->isOpaque(), &srcBM);
1155 } else
1156 #endif
1157 {
1158 srcBM = src->accessBitmap(false);
1159 }
1160
1161 SkCanvas c(dst);
1162
1163 SkAutoTUnref<SkImageFilter> localF(filter->newWithLocalMatrix(ctm));
1164 SkPaint p;
1165 p.setImageFilter(localF);
1166 const SkScalar x = SkIntToScalar(src->getOrigin().x());
1167 const SkScalar y = SkIntToScalar(src->getOrigin().y());
1168 c.drawBitmap(srcBM, x, y, &p);
1169 }
1170
make_layer_info(const SkImageInfo & prev,int w,int h,bool isOpaque,const SkPaint * paint)1171 static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque,
1172 const SkPaint* paint) {
1173 // need to force L32 for now if we have an image filter. Once filters support other colortypes
1174 // e.g. sRGB or F16, we can remove this check
1175 const bool hasImageFilter = paint && paint->getImageFilter();
1176
1177 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
1178 if ((prev.bytesPerPixel() < 4) || hasImageFilter) {
1179 // force to L32
1180 return SkImageInfo::MakeN32(w, h, alphaType);
1181 } else {
1182 // keep the same characteristics as the prev
1183 return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.profileType());
1184 }
1185 }
1186
internalSaveLayer(const SaveLayerRec & rec,SaveLayerStrategy strategy)1187 void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) {
1188 const SkRect* bounds = rec.fBounds;
1189 const SkPaint* paint = rec.fPaint;
1190 SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags;
1191
1192 #ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
1193 saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag;
1194 #endif
1195
1196 // do this before we create the layer. We don't call the public save() since
1197 // that would invoke a possibly overridden virtual
1198 this->internalSave();
1199
1200 fDeviceCMDirty = true;
1201
1202 SkIRect ir;
1203 if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, paint ? paint->getImageFilter() : nullptr)) {
1204 return;
1205 }
1206
1207 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about
1208 // the clipRectBounds() call above?
1209 if (kNoLayer_SaveLayerStrategy == strategy) {
1210 return;
1211 }
1212
1213 bool isOpaque = SkToBool(saveLayerFlags & kIsOpaque_SaveLayerFlag);
1214 SkPixelGeometry geo = fProps.pixelGeometry();
1215 if (paint) {
1216 // TODO: perhaps add a query to filters so we might preserve opaqueness...
1217 if (paint->getImageFilter() || paint->getColorFilter()) {
1218 isOpaque = false;
1219 geo = kUnknown_SkPixelGeometry;
1220 }
1221 }
1222
1223 SkBaseDevice* device = this->getTopDevice();
1224 if (nullptr == device) {
1225 SkDebugf("Unable to find device for layer.");
1226 return;
1227 }
1228
1229 SkImageInfo info = make_layer_info(device->imageInfo(), ir.width(), ir.height(), isOpaque,
1230 paint);
1231
1232 bool forceSpriteOnRestore = false;
1233 {
1234 const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() ||
1235 (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
1236 const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
1237 const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
1238 preserveLCDText, false);
1239 SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
1240 if (nullptr == newDev) {
1241 // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
1242 const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry);
1243 newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps);
1244 if (nullptr == newDev) {
1245 SkErrorInternals::SetError(kInternalError_SkError,
1246 "Unable to create device for layer.");
1247 return;
1248 }
1249 forceSpriteOnRestore = true;
1250 }
1251 device = newDev;
1252 }
1253 device->setOrigin(ir.fLeft, ir.fTop);
1254
1255 if (rec.fBackdrop) {
1256 draw_filter_into_device(fMCRec->fTopLayer->fDevice, rec.fBackdrop, device, fMCRec->fMatrix);
1257 }
1258
1259 DeviceCM* layer =
1260 new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore);
1261 device->unref();
1262
1263 layer->fNext = fMCRec->fTopLayer;
1264 fMCRec->fLayer = layer;
1265 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
1266 }
1267
saveLayerAlpha(const SkRect * bounds,U8CPU alpha)1268 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
1269 if (0xFF == alpha) {
1270 return this->saveLayer(bounds, nullptr);
1271 } else {
1272 SkPaint tmpPaint;
1273 tmpPaint.setAlpha(alpha);
1274 return this->saveLayer(bounds, &tmpPaint);
1275 }
1276 }
1277
internalRestore()1278 void SkCanvas::internalRestore() {
1279 SkASSERT(fMCStack.count() != 0);
1280
1281 fDeviceCMDirty = true;
1282 fCachedLocalClipBoundsDirty = true;
1283
1284 fClipStack->restore();
1285
1286 // reserve our layer (if any)
1287 DeviceCM* layer = fMCRec->fLayer; // may be null
1288 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1289 fMCRec->fLayer = nullptr;
1290
1291 // now do the normal restore()
1292 fMCRec->~MCRec(); // balanced in save()
1293 fMCStack.pop_back();
1294 fMCRec = (MCRec*)fMCStack.back();
1295
1296 /* Time to draw the layer's offscreen. We can't call the public drawSprite,
1297 since if we're being recorded, we don't want to record this (the
1298 recorder will have already recorded the restore).
1299 */
1300 if (layer) {
1301 if (layer->fNext) {
1302 const SkIPoint& origin = layer->fDevice->getOrigin();
1303 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
1304 layer->fPaint, layer->fDeviceIsBitmapDevice);
1305 // reset this, since internalDrawDevice will have set it to true
1306 fDeviceCMDirty = true;
1307 delete layer;
1308 } else {
1309 // we're at the root
1310 SkASSERT(layer == (void*)fDeviceCMStorage);
1311 layer->~DeviceCM();
1312 }
1313 }
1314 }
1315
newSurface(const SkImageInfo & info,const SkSurfaceProps * props)1316 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
1317 if (nullptr == props) {
1318 props = &fProps;
1319 }
1320 return this->onNewSurface(info, *props);
1321 }
1322
onNewSurface(const SkImageInfo & info,const SkSurfaceProps & props)1323 SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
1324 SkBaseDevice* dev = this->getDevice();
1325 return dev ? dev->newSurface(info, props) : nullptr;
1326 }
1327
imageInfo() const1328 SkImageInfo SkCanvas::imageInfo() const {
1329 SkBaseDevice* dev = this->getDevice();
1330 if (dev) {
1331 return dev->imageInfo();
1332 } else {
1333 return SkImageInfo::MakeUnknown(0, 0);
1334 }
1335 }
1336
peekPixels(SkImageInfo * info,size_t * rowBytes)1337 const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
1338 SkPixmap pmap;
1339 if (!this->onPeekPixels(&pmap)) {
1340 return nullptr;
1341 }
1342 if (info) {
1343 *info = pmap.info();
1344 }
1345 if (rowBytes) {
1346 *rowBytes = pmap.rowBytes();
1347 }
1348 return pmap.addr();
1349 }
1350
onPeekPixels(SkPixmap * pmap)1351 bool SkCanvas::onPeekPixels(SkPixmap* pmap) {
1352 SkBaseDevice* dev = this->getDevice();
1353 return dev && dev->peekPixels(pmap);
1354 }
1355
accessTopLayerPixels(SkImageInfo * info,size_t * rowBytes,SkIPoint * origin)1356 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin) {
1357 SkPixmap pmap;
1358 if (!this->onAccessTopLayerPixels(&pmap)) {
1359 return nullptr;
1360 }
1361 if (info) {
1362 *info = pmap.info();
1363 }
1364 if (rowBytes) {
1365 *rowBytes = pmap.rowBytes();
1366 }
1367 if (origin) {
1368 *origin = this->getTopDevice(false)->getOrigin();
1369 }
1370 return pmap.writable_addr();
1371 }
1372
onAccessTopLayerPixels(SkPixmap * pmap)1373 bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) {
1374 SkBaseDevice* dev = this->getTopDevice();
1375 return dev && dev->accessPixels(pmap);
1376 }
1377
1378 /////////////////////////////////////////////////////////////////////////////
1379
internalDrawDevice(SkBaseDevice * srcDev,int x,int y,const SkPaint * paint,bool deviceIsBitmapDevice)1380 void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
1381 const SkPaint* paint, bool deviceIsBitmapDevice) {
1382 SkPaint tmp;
1383 if (nullptr == paint) {
1384 paint = &tmp;
1385 }
1386
1387 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type)
1388 while (iter.next()) {
1389 SkBaseDevice* dstDev = iter.fDevice;
1390 paint = &looper.paint();
1391 SkImageFilter* filter = paint->getImageFilter();
1392 SkIPoint pos = { x - iter.getX(), y - iter.getY() };
1393 if (filter && !dstDev->canHandleImageFilter(filter)) {
1394 SkImageFilter::DeviceProxy proxy(dstDev);
1395 SkBitmap dst;
1396 SkIPoint offset = SkIPoint::Make(0, 0);
1397 const SkBitmap& src = srcDev->accessBitmap(false);
1398 SkMatrix matrix = *iter.fMatrix;
1399 matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
1400 SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
1401 SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
1402 SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
1403 if (filter->filterImageDeprecated(&proxy, src, ctx, &dst, &offset)) {
1404 SkPaint tmpUnfiltered(*paint);
1405 tmpUnfiltered.setImageFilter(nullptr);
1406 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
1407 tmpUnfiltered);
1408 }
1409 } else if (deviceIsBitmapDevice) {
1410 const SkBitmap& src = static_cast<SkBitmapDevice*>(srcDev)->fBitmap;
1411 dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
1412 } else {
1413 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
1414 }
1415 }
1416 LOOPER_END
1417 }
1418
1419 /////////////////////////////////////////////////////////////////////////////
1420
translate(SkScalar dx,SkScalar dy)1421 void SkCanvas::translate(SkScalar dx, SkScalar dy) {
1422 SkMatrix m;
1423 m.setTranslate(dx, dy);
1424 this->concat(m);
1425 }
1426
scale(SkScalar sx,SkScalar sy)1427 void SkCanvas::scale(SkScalar sx, SkScalar sy) {
1428 SkMatrix m;
1429 m.setScale(sx, sy);
1430 this->concat(m);
1431 }
1432
rotate(SkScalar degrees)1433 void SkCanvas::rotate(SkScalar degrees) {
1434 SkMatrix m;
1435 m.setRotate(degrees);
1436 this->concat(m);
1437 }
1438
skew(SkScalar sx,SkScalar sy)1439 void SkCanvas::skew(SkScalar sx, SkScalar sy) {
1440 SkMatrix m;
1441 m.setSkew(sx, sy);
1442 this->concat(m);
1443 }
1444
concat(const SkMatrix & matrix)1445 void SkCanvas::concat(const SkMatrix& matrix) {
1446 if (matrix.isIdentity()) {
1447 return;
1448 }
1449
1450 this->checkForDeferredSave();
1451 fDeviceCMDirty = true;
1452 fCachedLocalClipBoundsDirty = true;
1453 fMCRec->fMatrix.preConcat(matrix);
1454
1455 this->didConcat(matrix);
1456 }
1457
setMatrix(const SkMatrix & matrix)1458 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1459 this->checkForDeferredSave();
1460 fDeviceCMDirty = true;
1461 fCachedLocalClipBoundsDirty = true;
1462 fMCRec->fMatrix = matrix;
1463 this->didSetMatrix(matrix);
1464 }
1465
resetMatrix()1466 void SkCanvas::resetMatrix() {
1467 SkMatrix matrix;
1468
1469 matrix.reset();
1470 this->setMatrix(matrix);
1471 }
1472
1473 //////////////////////////////////////////////////////////////////////////////
1474
clipRect(const SkRect & rect,SkRegion::Op op,bool doAA)1475 void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
1476 this->checkForDeferredSave();
1477 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1478 this->onClipRect(rect, op, edgeStyle);
1479 }
1480
onClipRect(const SkRect & rect,SkRegion::Op op,ClipEdgeStyle edgeStyle)1481 void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1482 #ifdef SK_ENABLE_CLIP_QUICKREJECT
1483 if (SkRegion::kIntersect_Op == op) {
1484 if (fMCRec->fRasterClip.isEmpty()) {
1485 return false;
1486 }
1487
1488 if (this->quickReject(rect)) {
1489 fDeviceCMDirty = true;
1490 fCachedLocalClipBoundsDirty = true;
1491
1492 fClipStack->clipEmpty();
1493 return fMCRec->fRasterClip.setEmpty();
1494 }
1495 }
1496 #endif
1497
1498 if (!fAllowSoftClip) {
1499 edgeStyle = kHard_ClipEdgeStyle;
1500 }
1501
1502 const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect();
1503 SkRect devR;
1504 if (rectStaysRect) {
1505 fMCRec->fMatrix.mapRect(&devR, rect);
1506 }
1507
1508 // Check if we can quick-accept the clip call (and do nothing)
1509 //
1510 // TODO: investigate if a (conservative) version of this could be done in ::clipRect,
1511 // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn
1512 // might allow lazy save/restores to eliminate entire save/restore blocks.
1513 //
1514 if (SkRegion::kIntersect_Op == op &&
1515 kHard_ClipEdgeStyle == edgeStyle
1516 && rectStaysRect)
1517 {
1518 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1519 #if 0
1520 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1521 rect.left(), rect.top(), rect.right(), rect.bottom());
1522 #endif
1523 return;
1524 }
1525 }
1526
1527 AutoValidateClip avc(this);
1528
1529 fDeviceCMDirty = true;
1530 fCachedLocalClipBoundsDirty = true;
1531
1532 if (rectStaysRect) {
1533 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1534 fClipStack->clipDevRect(devR, op, isAA);
1535 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
1536 } else {
1537 // since we're rotated or some such thing, we convert the rect to a path
1538 // and clip against that, since it can handle any matrix. However, to
1539 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1540 // we explicitly call "our" version of clipPath.
1541 SkPath path;
1542
1543 path.addRect(rect);
1544 this->SkCanvas::onClipPath(path, op, edgeStyle);
1545 }
1546 }
1547
clipRRect(const SkRRect & rrect,SkRegion::Op op,bool doAA)1548 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
1549 this->checkForDeferredSave();
1550 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1551 if (rrect.isRect()) {
1552 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1553 } else {
1554 this->onClipRRect(rrect, op, edgeStyle);
1555 }
1556 }
1557
onClipRRect(const SkRRect & rrect,SkRegion::Op op,ClipEdgeStyle edgeStyle)1558 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1559 SkRRect transformedRRect;
1560 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
1561 AutoValidateClip avc(this);
1562
1563 fDeviceCMDirty = true;
1564 fCachedLocalClipBoundsDirty = true;
1565 if (!fAllowSoftClip) {
1566 edgeStyle = kHard_ClipEdgeStyle;
1567 }
1568
1569 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle);
1570
1571 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
1572 kSoft_ClipEdgeStyle == edgeStyle);
1573 return;
1574 }
1575
1576 SkPath path;
1577 path.addRRect(rrect);
1578 // call the non-virtual version
1579 this->SkCanvas::onClipPath(path, op, edgeStyle);
1580 }
1581
clipPath(const SkPath & path,SkRegion::Op op,bool doAA)1582 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
1583 this->checkForDeferredSave();
1584 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1585
1586 if (!path.isInverseFillType() && fMCRec->fMatrix.rectStaysRect()) {
1587 SkRect r;
1588 if (path.isRect(&r)) {
1589 this->onClipRect(r, op, edgeStyle);
1590 return;
1591 }
1592 SkRRect rrect;
1593 if (path.isOval(&r)) {
1594 rrect.setOval(r);
1595 this->onClipRRect(rrect, op, edgeStyle);
1596 return;
1597 }
1598 if (path.isRRect(&rrect)) {
1599 this->onClipRRect(rrect, op, edgeStyle);
1600 return;
1601 }
1602 }
1603
1604 this->onClipPath(path, op, edgeStyle);
1605 }
1606
onClipPath(const SkPath & path,SkRegion::Op op,ClipEdgeStyle edgeStyle)1607 void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1608 #ifdef SK_ENABLE_CLIP_QUICKREJECT
1609 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) {
1610 if (fMCRec->fRasterClip.isEmpty()) {
1611 return false;
1612 }
1613
1614 if (this->quickReject(path.getBounds())) {
1615 fDeviceCMDirty = true;
1616 fCachedLocalClipBoundsDirty = true;
1617
1618 fClipStack->clipEmpty();
1619 return fMCRec->fRasterClip.setEmpty();
1620 }
1621 }
1622 #endif
1623
1624 AutoValidateClip avc(this);
1625
1626 fDeviceCMDirty = true;
1627 fCachedLocalClipBoundsDirty = true;
1628 if (!fAllowSoftClip) {
1629 edgeStyle = kHard_ClipEdgeStyle;
1630 }
1631
1632 SkPath devPath;
1633 path.transform(fMCRec->fMatrix, &devPath);
1634
1635 // Check if the transfomation, or the original path itself
1636 // made us empty. Note this can also happen if we contained NaN
1637 // values. computing the bounds detects this, and will set our
1638 // bounds to empty if that is the case. (see SkRect::set(pts, count))
1639 if (devPath.getBounds().isEmpty()) {
1640 // resetting the path will remove any NaN or other wanky values
1641 // that might upset our scan converter.
1642 devPath.reset();
1643 }
1644
1645 // if we called path.swap() we could avoid a deep copy of this path
1646 fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle);
1647
1648 if (fAllowSimplifyClip) {
1649 bool clipIsAA = getClipStack()->asPath(&devPath);
1650 if (clipIsAA) {
1651 edgeStyle = kSoft_ClipEdgeStyle;
1652 }
1653
1654 op = SkRegion::kReplace_Op;
1655 }
1656
1657 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
1658 }
1659
clipRegion(const SkRegion & rgn,SkRegion::Op op)1660 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1661 this->checkForDeferredSave();
1662 this->onClipRegion(rgn, op);
1663 }
1664
onClipRegion(const SkRegion & rgn,SkRegion::Op op)1665 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
1666 AutoValidateClip avc(this);
1667
1668 fDeviceCMDirty = true;
1669 fCachedLocalClipBoundsDirty = true;
1670
1671 // todo: signal fClipStack that we have a region, and therefore (I guess)
1672 // we have to ignore it, and use the region directly?
1673 fClipStack->clipDevRect(rgn.getBounds(), op);
1674
1675 fMCRec->fRasterClip.op(rgn, op);
1676 }
1677
1678 #ifdef SK_DEBUG
validateClip() const1679 void SkCanvas::validateClip() const {
1680 // construct clipRgn from the clipstack
1681 const SkBaseDevice* device = this->getDevice();
1682 if (!device) {
1683 SkASSERT(this->isClipEmpty());
1684 return;
1685 }
1686
1687 SkIRect ir;
1688 ir.set(0, 0, device->width(), device->height());
1689 SkRasterClip tmpClip(ir, fConservativeRasterClip);
1690
1691 SkClipStack::B2TIter iter(*fClipStack);
1692 const SkClipStack::Element* element;
1693 while ((element = iter.next()) != nullptr) {
1694 switch (element->getType()) {
1695 case SkClipStack::Element::kRect_Type:
1696 element->getRect().round(&ir);
1697 tmpClip.op(ir, element->getOp());
1698 break;
1699 case SkClipStack::Element::kEmpty_Type:
1700 tmpClip.setEmpty();
1701 break;
1702 default: {
1703 SkPath path;
1704 element->asPath(&path);
1705 tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA());
1706 break;
1707 }
1708 }
1709 }
1710 }
1711 #endif
1712
replayClips(ClipVisitor * visitor) const1713 void SkCanvas::replayClips(ClipVisitor* visitor) const {
1714 SkClipStack::B2TIter iter(*fClipStack);
1715 const SkClipStack::Element* element;
1716
1717 while ((element = iter.next()) != nullptr) {
1718 element->replay(visitor);
1719 }
1720 }
1721
1722 ///////////////////////////////////////////////////////////////////////////////
1723
isClipEmpty() const1724 bool SkCanvas::isClipEmpty() const {
1725 return fMCRec->fRasterClip.isEmpty();
1726 }
1727
isClipRect() const1728 bool SkCanvas::isClipRect() const {
1729 return fMCRec->fRasterClip.isRect();
1730 }
1731
quickReject(const SkRect & rect) const1732 bool SkCanvas::quickReject(const SkRect& rect) const {
1733 if (!rect.isFinite())
1734 return true;
1735
1736 if (fMCRec->fRasterClip.isEmpty()) {
1737 return true;
1738 }
1739
1740 if (fMCRec->fMatrix.hasPerspective()) {
1741 SkRect dst;
1742 fMCRec->fMatrix.mapRect(&dst, rect);
1743 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
1744 } else {
1745 const SkRect& clipR = this->getLocalClipBounds();
1746
1747 // for speed, do the most likely reject compares first
1748 // TODO: should we use | instead, or compare all 4 at once?
1749 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
1750 return true;
1751 }
1752 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
1753 return true;
1754 }
1755 return false;
1756 }
1757 }
1758
quickReject(const SkPath & path) const1759 bool SkCanvas::quickReject(const SkPath& path) const {
1760 return path.isEmpty() || this->quickReject(path.getBounds());
1761 }
1762
getClipBounds(SkRect * bounds) const1763 bool SkCanvas::getClipBounds(SkRect* bounds) const {
1764 SkIRect ibounds;
1765 if (!this->getClipDeviceBounds(&ibounds)) {
1766 return false;
1767 }
1768
1769 SkMatrix inverse;
1770 // if we can't invert the CTM, we can't return local clip bounds
1771 if (!fMCRec->fMatrix.invert(&inverse)) {
1772 if (bounds) {
1773 bounds->setEmpty();
1774 }
1775 return false;
1776 }
1777
1778 if (bounds) {
1779 SkRect r;
1780 // adjust it outwards in case we are antialiasing
1781 const int inset = 1;
1782
1783 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1784 ibounds.fRight + inset, ibounds.fBottom + inset);
1785 inverse.mapRect(bounds, r);
1786 }
1787 return true;
1788 }
1789
getClipDeviceBounds(SkIRect * bounds) const1790 bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
1791 const SkRasterClip& clip = fMCRec->fRasterClip;
1792 if (clip.isEmpty()) {
1793 if (bounds) {
1794 bounds->setEmpty();
1795 }
1796 return false;
1797 }
1798
1799 if (bounds) {
1800 *bounds = clip.getBounds();
1801 }
1802 return true;
1803 }
1804
getTotalMatrix() const1805 const SkMatrix& SkCanvas::getTotalMatrix() const {
1806 return fMCRec->fMatrix;
1807 }
1808
internal_private_getTotalClip() const1809 const SkRegion& SkCanvas::internal_private_getTotalClip() const {
1810 return fMCRec->fRasterClip.forceGetBW();
1811 }
1812
internal_private_accessTopLayerRenderTarget()1813 GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() {
1814 SkBaseDevice* dev = this->getTopDevice();
1815 return dev ? dev->accessRenderTarget() : nullptr;
1816 }
1817
getGrContext()1818 GrContext* SkCanvas::getGrContext() {
1819 #if SK_SUPPORT_GPU
1820 SkBaseDevice* device = this->getTopDevice();
1821 if (device) {
1822 GrRenderTarget* renderTarget = device->accessRenderTarget();
1823 if (renderTarget) {
1824 return renderTarget->getContext();
1825 }
1826 }
1827 #endif
1828
1829 return nullptr;
1830
1831 }
1832
drawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)1833 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner,
1834 const SkPaint& paint) {
1835 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawDRRect()");
1836 if (outer.isEmpty()) {
1837 return;
1838 }
1839 if (inner.isEmpty()) {
1840 this->drawRRect(outer, paint);
1841 return;
1842 }
1843
1844 // We don't have this method (yet), but technically this is what we should
1845 // be able to assert...
1846 // SkASSERT(outer.contains(inner));
1847 //
1848 // For now at least check for containment of bounds
1849 SkASSERT(outer.getBounds().contains(inner.getBounds()));
1850
1851 this->onDrawDRRect(outer, inner, paint);
1852 }
1853
1854 // These need to stop being virtual -- clients need to override the onDraw... versions
1855
drawPaint(const SkPaint & paint)1856 void SkCanvas::drawPaint(const SkPaint& paint) {
1857 this->onDrawPaint(paint);
1858 }
1859
drawRect(const SkRect & r,const SkPaint & paint)1860 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1861 this->onDrawRect(r, paint);
1862 }
1863
drawOval(const SkRect & r,const SkPaint & paint)1864 void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) {
1865 this->onDrawOval(r, paint);
1866 }
1867
drawRRect(const SkRRect & rrect,const SkPaint & paint)1868 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1869 this->onDrawRRect(rrect, paint);
1870 }
1871
drawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)1872 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) {
1873 this->onDrawPoints(mode, count, pts, paint);
1874 }
1875
drawVertices(VertexMode vmode,int vertexCount,const SkPoint vertices[],const SkPoint texs[],const SkColor colors[],SkXfermode * xmode,const uint16_t indices[],int indexCount,const SkPaint & paint)1876 void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
1877 const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
1878 const uint16_t indices[], int indexCount, const SkPaint& paint) {
1879 this->onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
1880 indices, indexCount, paint);
1881 }
1882
drawPath(const SkPath & path,const SkPaint & paint)1883 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1884 this->onDrawPath(path, paint);
1885 }
1886
drawImage(const SkImage * image,SkScalar x,SkScalar y,const SkPaint * paint)1887 void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
1888 RETURN_ON_NULL(image);
1889 this->onDrawImage(image, x, y, paint);
1890 }
1891
drawImageRect(const SkImage * image,const SkRect & src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1892 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
1893 const SkPaint* paint, SrcRectConstraint constraint) {
1894 RETURN_ON_NULL(image);
1895 if (dst.isEmpty() || src.isEmpty()) {
1896 return;
1897 }
1898 this->onDrawImageRect(image, &src, dst, paint, constraint);
1899 }
1900
drawImageRect(const SkImage * image,const SkIRect & isrc,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1901 void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
1902 const SkPaint* paint, SrcRectConstraint constraint) {
1903 RETURN_ON_NULL(image);
1904 this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
1905 }
1906
drawImageRect(const SkImage * image,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1907 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
1908 SrcRectConstraint constraint) {
1909 RETURN_ON_NULL(image);
1910 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
1911 constraint);
1912 }
1913
drawImageNine(const SkImage * image,const SkIRect & center,const SkRect & dst,const SkPaint * paint)1914 void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
1915 const SkPaint* paint) {
1916 RETURN_ON_NULL(image);
1917 if (dst.isEmpty()) {
1918 return;
1919 }
1920 if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
1921 this->drawImageRect(image, dst, paint);
1922 }
1923 this->onDrawImageNine(image, center, dst, paint);
1924 }
1925
drawBitmap(const SkBitmap & bitmap,SkScalar dx,SkScalar dy,const SkPaint * paint)1926 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
1927 if (bitmap.drawsNothing()) {
1928 return;
1929 }
1930 this->onDrawBitmap(bitmap, dx, dy, paint);
1931 }
1932
drawBitmapRect(const SkBitmap & bitmap,const SkRect & src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1933 void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
1934 const SkPaint* paint, SrcRectConstraint constraint) {
1935 if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
1936 return;
1937 }
1938 this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
1939 }
1940
drawBitmapRect(const SkBitmap & bitmap,const SkIRect & isrc,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1941 void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
1942 const SkPaint* paint, SrcRectConstraint constraint) {
1943 this->drawBitmapRect(bitmap, SkRect::Make(isrc), dst, paint, constraint);
1944 }
1945
drawBitmapRect(const SkBitmap & bitmap,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1946 void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
1947 SrcRectConstraint constraint) {
1948 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()), dst, paint,
1949 constraint);
1950 }
1951
drawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)1952 void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
1953 const SkPaint* paint) {
1954 if (bitmap.drawsNothing() || dst.isEmpty()) {
1955 return;
1956 }
1957 if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
1958 this->drawBitmapRect(bitmap, dst, paint);
1959 }
1960 this->onDrawBitmapNine(bitmap, center, dst, paint);
1961 }
1962
drawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkXfermode::Mode mode,const SkRect * cull,const SkPaint * paint)1963 void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
1964 const SkColor colors[], int count, SkXfermode::Mode mode,
1965 const SkRect* cull, const SkPaint* paint) {
1966 RETURN_ON_NULL(atlas);
1967 if (count <= 0) {
1968 return;
1969 }
1970 SkASSERT(atlas);
1971 SkASSERT(xform);
1972 SkASSERT(tex);
1973 this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
1974 }
1975
legacy_drawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1976 void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1977 const SkPaint* paint, SrcRectConstraint constraint) {
1978 if (src) {
1979 this->drawImageRect(image, *src, dst, paint, constraint);
1980 } else {
1981 this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()),
1982 dst, paint, constraint);
1983 }
1984 }
legacy_drawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)1985 void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1986 const SkPaint* paint, SrcRectConstraint constraint) {
1987 if (src) {
1988 this->drawBitmapRect(bitmap, *src, dst, paint, constraint);
1989 } else {
1990 this->drawBitmapRect(bitmap, SkRect::MakeIWH(bitmap.width(), bitmap.height()),
1991 dst, paint, constraint);
1992 }
1993 }
1994
1995 //////////////////////////////////////////////////////////////////////////////
1996 // These are the virtual drawing methods
1997 //////////////////////////////////////////////////////////////////////////////
1998
onDiscard()1999 void SkCanvas::onDiscard() {
2000 if (fSurfaceBase) {
2001 fSurfaceBase->aboutToDraw(SkSurface::kDiscard_ContentChangeMode);
2002 }
2003 }
2004
onDrawPaint(const SkPaint & paint)2005 void SkCanvas::onDrawPaint(const SkPaint& paint) {
2006 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPaint()");
2007 this->internalDrawPaint(paint);
2008 }
2009
internalDrawPaint(const SkPaint & paint)2010 void SkCanvas::internalDrawPaint(const SkPaint& paint) {
2011 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kPaint_Type, nullptr, false)
2012
2013 while (iter.next()) {
2014 iter.fDevice->drawPaint(iter, looper.paint());
2015 }
2016
2017 LOOPER_END
2018 }
2019
onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)2020 void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
2021 const SkPaint& paint) {
2022 TRACE_EVENT1("disabled-by-default-skia", "SkCanvas::drawPoints()", "count", static_cast<uint64_t>(count));
2023 if ((long)count <= 0) {
2024 return;
2025 }
2026
2027 SkRect r, storage;
2028 const SkRect* bounds = nullptr;
2029 if (paint.canComputeFastBounds()) {
2030 // special-case 2 points (common for drawing a single line)
2031 if (2 == count) {
2032 r.set(pts[0], pts[1]);
2033 } else {
2034 r.set(pts, SkToInt(count));
2035 }
2036 if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
2037 return;
2038 }
2039 bounds = &r;
2040 }
2041
2042 SkASSERT(pts != nullptr);
2043
2044 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds)
2045
2046 while (iter.next()) {
2047 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
2048 }
2049
2050 LOOPER_END
2051 }
2052
onDrawRect(const SkRect & r,const SkPaint & paint)2053 void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
2054 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()");
2055 SkRect storage;
2056 const SkRect* bounds = nullptr;
2057 if (paint.canComputeFastBounds()) {
2058 // Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
2059 // To prevent accidental rejecting at this stage, we have to sort it before we check.
2060 SkRect tmp(r);
2061 tmp.sort();
2062
2063 if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
2064 return;
2065 }
2066 bounds = &r;
2067 }
2068
2069 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false)
2070
2071 while (iter.next()) {
2072 iter.fDevice->drawRect(iter, r, looper.paint());
2073 }
2074
2075 LOOPER_END
2076 }
2077
onDrawOval(const SkRect & oval,const SkPaint & paint)2078 void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
2079 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
2080 SkRect storage;
2081 const SkRect* bounds = nullptr;
2082 if (paint.canComputeFastBounds()) {
2083 if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
2084 return;
2085 }
2086 bounds = &oval;
2087 }
2088
2089 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds)
2090
2091 while (iter.next()) {
2092 iter.fDevice->drawOval(iter, oval, looper.paint());
2093 }
2094
2095 LOOPER_END
2096 }
2097
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)2098 void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
2099 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()");
2100 SkRect storage;
2101 const SkRect* bounds = nullptr;
2102 if (paint.canComputeFastBounds()) {
2103 if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) {
2104 return;
2105 }
2106 bounds = &rrect.getBounds();
2107 }
2108
2109 if (rrect.isRect()) {
2110 // call the non-virtual version
2111 this->SkCanvas::drawRect(rrect.getBounds(), paint);
2112 return;
2113 } else if (rrect.isOval()) {
2114 // call the non-virtual version
2115 this->SkCanvas::drawOval(rrect.getBounds(), paint);
2116 return;
2117 }
2118
2119 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
2120
2121 while (iter.next()) {
2122 iter.fDevice->drawRRect(iter, rrect, looper.paint());
2123 }
2124
2125 LOOPER_END
2126 }
2127
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)2128 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
2129 const SkPaint& paint) {
2130 SkRect storage;
2131 const SkRect* bounds = nullptr;
2132 if (paint.canComputeFastBounds()) {
2133 if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) {
2134 return;
2135 }
2136 bounds = &outer.getBounds();
2137 }
2138
2139 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds)
2140
2141 while (iter.next()) {
2142 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint());
2143 }
2144
2145 LOOPER_END
2146 }
2147
onDrawPath(const SkPath & path,const SkPaint & paint)2148 void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
2149 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPath()");
2150 if (!path.isFinite()) {
2151 return;
2152 }
2153
2154 SkRect storage;
2155 const SkRect* bounds = nullptr;
2156 if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
2157 const SkRect& pathBounds = path.getBounds();
2158 if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) {
2159 return;
2160 }
2161 bounds = &pathBounds;
2162 }
2163
2164 const SkRect& r = path.getBounds();
2165 if (r.width() <= 0 && r.height() <= 0) {
2166 if (path.isInverseFillType()) {
2167 this->internalDrawPaint(paint);
2168 return;
2169 }
2170 }
2171
2172 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds)
2173
2174 while (iter.next()) {
2175 iter.fDevice->drawPath(iter, path, looper.paint());
2176 }
2177
2178 LOOPER_END
2179 }
2180
canDrawBitmapAsSprite(SkScalar x,SkScalar y,int w,int h,const SkPaint & paint)2181 bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint& paint) {
2182 if (!paint.getImageFilter()) {
2183 return false;
2184 }
2185
2186 const SkMatrix& ctm = this->getTotalMatrix();
2187 if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) {
2188 return false;
2189 }
2190
2191 // Currently we can only use the filterSprite code if we are clipped to the bitmap's bounds.
2192 // Once we can filter and the filter will return a result larger than itself, we should be
2193 // able to remove this constraint.
2194 // skbug.com/4526
2195 //
2196 SkPoint pt;
2197 ctm.mapXY(x, y, &pt);
2198 SkIRect ir = SkIRect::MakeXYWH(SkScalarRoundToInt(pt.x()), SkScalarRoundToInt(pt.y()), w, h);
2199 return ir.contains(fMCRec->fRasterClip.getBounds());
2200 }
2201
onDrawImage(const SkImage * image,SkScalar x,SkScalar y,const SkPaint * paint)2202 void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
2203 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
2204 SkRect bounds = SkRect::MakeXYWH(x, y,
2205 SkIntToScalar(image->width()), SkIntToScalar(image->height()));
2206 if (nullptr == paint || paint->canComputeFastBounds()) {
2207 SkRect tmp = bounds;
2208 if (paint) {
2209 paint->computeFastBounds(tmp, &tmp);
2210 }
2211 if (this->quickReject(tmp)) {
2212 return;
2213 }
2214 }
2215
2216 SkLazyPaint lazy;
2217 if (nullptr == paint) {
2218 paint = lazy.init();
2219 }
2220
2221 bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(),
2222 *paint);
2223 if (drawAsSprite && paint->getImageFilter()) {
2224 SkBitmap bitmap;
2225 if (!as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2226 drawAsSprite = false;
2227 } else{
2228 // Until imagefilters are updated, they cannot handle any src type but N32...
2229 if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) {
2230 drawAsSprite = false;
2231 }
2232 }
2233 }
2234
2235 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds)
2236
2237 while (iter.next()) {
2238 const SkPaint& pnt = looper.paint();
2239 if (drawAsSprite && pnt.getImageFilter()) {
2240 SkBitmap bitmap;
2241 if (as_IB(image)->asBitmapForImageFilters(&bitmap)) {
2242 SkPoint pt;
2243 iter.fMatrix->mapXY(x, y, &pt);
2244 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2245 SkScalarRoundToInt(pt.fX),
2246 SkScalarRoundToInt(pt.fY), pnt);
2247 }
2248 } else {
2249 iter.fDevice->drawImage(iter, image, x, y, pnt);
2250 }
2251 }
2252
2253 LOOPER_END
2254 }
2255
onDrawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2256 void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
2257 const SkPaint* paint, SrcRectConstraint constraint) {
2258 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
2259 if (nullptr == paint || paint->canComputeFastBounds()) {
2260 SkRect storage = dst;
2261 if (paint) {
2262 paint->computeFastBounds(dst, &storage);
2263 }
2264 if (this->quickReject(storage)) {
2265 return;
2266 }
2267 }
2268 SkLazyPaint lazy;
2269 if (nullptr == paint) {
2270 paint = lazy.init();
2271 }
2272
2273 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
2274 image->isOpaque())
2275
2276 while (iter.next()) {
2277 iter.fDevice->drawImageRect(iter, image, src, dst, looper.paint(), constraint);
2278 }
2279
2280 LOOPER_END
2281 }
2282
onDrawBitmap(const SkBitmap & bitmap,SkScalar x,SkScalar y,const SkPaint * paint)2283 void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {
2284 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmap()");
2285 SkDEBUGCODE(bitmap.validate();)
2286
2287 if (bitmap.drawsNothing()) {
2288 return;
2289 }
2290
2291 SkLazyPaint lazy;
2292 if (nullptr == paint) {
2293 paint = lazy.init();
2294 }
2295
2296 const SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2297
2298 SkRect storage;
2299 const SkRect* bounds = nullptr;
2300 if (paint->canComputeFastBounds()) {
2301 bitmap.getBounds(&storage);
2302 matrix.mapRect(&storage);
2303 SkRect tmp = storage;
2304 if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) {
2305 return;
2306 }
2307 bounds = &storage;
2308 }
2309
2310 bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(),
2311 *paint);
2312 if (drawAsSprite && paint->getImageFilter()) {
2313 // Until imagefilters are updated, they cannot handle any src type but N32...
2314 if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) {
2315 drawAsSprite = false;
2316 }
2317 }
2318
2319 LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds)
2320
2321 while (iter.next()) {
2322 const SkPaint& pnt = looper.paint();
2323 if (drawAsSprite && pnt.getImageFilter()) {
2324 SkPoint pt;
2325 iter.fMatrix->mapXY(x, y, &pt);
2326 iter.fDevice->drawBitmapAsSprite(iter, bitmap,
2327 SkScalarRoundToInt(pt.fX),
2328 SkScalarRoundToInt(pt.fY), pnt);
2329 } else {
2330 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2331 }
2332 }
2333
2334 LOOPER_END
2335 }
2336
2337 // this one is non-virtual, so it can be called safely by other canvas apis
internalDrawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2338 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
2339 const SkRect& dst, const SkPaint* paint,
2340 SrcRectConstraint constraint) {
2341 if (bitmap.drawsNothing() || dst.isEmpty()) {
2342 return;
2343 }
2344
2345 if (nullptr == paint || paint->canComputeFastBounds()) {
2346 SkRect storage;
2347 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2348 return;
2349 }
2350 }
2351
2352 SkLazyPaint lazy;
2353 if (nullptr == paint) {
2354 paint = lazy.init();
2355 }
2356
2357 LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(*paint, SkDrawFilter::kBitmap_Type, &dst,
2358 bitmap.isOpaque())
2359
2360 while (iter.next()) {
2361 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), constraint);
2362 }
2363
2364 LOOPER_END
2365 }
2366
onDrawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)2367 void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
2368 const SkPaint* paint, SrcRectConstraint constraint) {
2369 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapRectToRect()");
2370 SkDEBUGCODE(bitmap.validate();)
2371 this->internalDrawBitmapRect(bitmap, src, dst, paint, constraint);
2372 }
2373
onDrawImageNine(const SkImage * image,const SkIRect & center,const SkRect & dst,const SkPaint * paint)2374 void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
2375 const SkPaint* paint) {
2376 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
2377
2378 if (nullptr == paint || paint->canComputeFastBounds()) {
2379 SkRect storage;
2380 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2381 return;
2382 }
2383 }
2384
2385 SkLazyPaint lazy;
2386 if (nullptr == paint) {
2387 paint = lazy.init();
2388 }
2389
2390 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2391
2392 while (iter.next()) {
2393 iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
2394 }
2395
2396 LOOPER_END
2397 }
2398
onDrawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)2399 void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
2400 const SkPaint* paint) {
2401 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
2402 SkDEBUGCODE(bitmap.validate();)
2403
2404 if (nullptr == paint || paint->canComputeFastBounds()) {
2405 SkRect storage;
2406 if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
2407 return;
2408 }
2409 }
2410
2411 SkLazyPaint lazy;
2412 if (nullptr == paint) {
2413 paint = lazy.init();
2414 }
2415
2416 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
2417
2418 while (iter.next()) {
2419 iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
2420 }
2421
2422 LOOPER_END
2423 }
2424
2425 class SkDeviceFilteredPaint {
2426 public:
SkDeviceFilteredPaint(SkBaseDevice * device,const SkPaint & paint)2427 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
2428 uint32_t filteredFlags = device->filterTextFlags(paint);
2429 if (filteredFlags != paint.getFlags()) {
2430 SkPaint* newPaint = fLazy.set(paint);
2431 newPaint->setFlags(filteredFlags);
2432 fPaint = newPaint;
2433 } else {
2434 fPaint = &paint;
2435 }
2436 }
2437
paint() const2438 const SkPaint& paint() const { return *fPaint; }
2439
2440 private:
2441 const SkPaint* fPaint;
2442 SkLazyPaint fLazy;
2443 };
2444
DrawRect(const SkDraw & draw,const SkPaint & paint,const SkRect & r,SkScalar textSize)2445 void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
2446 const SkRect& r, SkScalar textSize) {
2447 if (paint.getStyle() == SkPaint::kFill_Style) {
2448 draw.fDevice->drawRect(draw, r, paint);
2449 } else {
2450 SkPaint p(paint);
2451 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
2452 draw.fDevice->drawRect(draw, r, p);
2453 }
2454 }
2455
DrawTextDecorations(const SkDraw & draw,const SkPaint & paint,const char text[],size_t byteLength,SkScalar x,SkScalar y)2456 void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
2457 const char text[], size_t byteLength,
2458 SkScalar x, SkScalar y) {
2459 SkASSERT(byteLength == 0 || text != nullptr);
2460
2461 // nothing to draw
2462 if (text == nullptr || byteLength == 0 ||
2463 draw.fClip->isEmpty() ||
2464 (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) {
2465 return;
2466 }
2467
2468 SkScalar width = 0;
2469 SkPoint start;
2470
2471 start.set(0, 0); // to avoid warning
2472 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
2473 SkPaint::kStrikeThruText_Flag)) {
2474 width = paint.measureText(text, byteLength);
2475
2476 SkScalar offsetX = 0;
2477 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2478 offsetX = SkScalarHalf(width);
2479 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
2480 offsetX = width;
2481 }
2482 start.set(x - offsetX, y);
2483 }
2484
2485 if (0 == width) {
2486 return;
2487 }
2488
2489 uint32_t flags = paint.getFlags();
2490
2491 if (flags & (SkPaint::kUnderlineText_Flag |
2492 SkPaint::kStrikeThruText_Flag)) {
2493 SkScalar textSize = paint.getTextSize();
2494 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
2495 SkRect r;
2496
2497 r.fLeft = start.fX;
2498 r.fRight = start.fX + width;
2499
2500 if (flags & SkPaint::kUnderlineText_Flag) {
2501 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
2502 start.fY);
2503 r.fTop = offset;
2504 r.fBottom = offset + height;
2505 DrawRect(draw, paint, r, 1);
2506 }
2507 if (flags & SkPaint::kStrikeThruText_Flag) {
2508 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
2509 start.fY);
2510 r.fTop = offset;
2511 r.fBottom = offset + height;
2512 DrawRect(draw, paint, r, 1);
2513 }
2514 }
2515 }
2516
onDrawText(const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)2517 void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2518 const SkPaint& paint) {
2519 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2520
2521 while (iter.next()) {
2522 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2523 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
2524 DrawTextDecorations(iter, dfp.paint(),
2525 static_cast<const char*>(text), byteLength, x, y);
2526 }
2527
2528 LOOPER_END
2529 }
2530
onDrawPosText(const void * text,size_t byteLength,const SkPoint pos[],const SkPaint & paint)2531 void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2532 const SkPaint& paint) {
2533 SkPoint textOffset = SkPoint::Make(0, 0);
2534
2535 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2536
2537 while (iter.next()) {
2538 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2539 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 2, textOffset,
2540 dfp.paint());
2541 }
2542
2543 LOOPER_END
2544 }
2545
onDrawPosTextH(const void * text,size_t byteLength,const SkScalar xpos[],SkScalar constY,const SkPaint & paint)2546 void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2547 SkScalar constY, const SkPaint& paint) {
2548
2549 SkPoint textOffset = SkPoint::Make(0, constY);
2550
2551 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2552
2553 while (iter.next()) {
2554 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2555 iter.fDevice->drawPosText(iter, text, byteLength, xpos, 1, textOffset,
2556 dfp.paint());
2557 }
2558
2559 LOOPER_END
2560 }
2561
onDrawTextOnPath(const void * text,size_t byteLength,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)2562 void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2563 const SkMatrix* matrix, const SkPaint& paint) {
2564 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
2565
2566 while (iter.next()) {
2567 iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
2568 matrix, looper.paint());
2569 }
2570
2571 LOOPER_END
2572 }
2573
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)2574 void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2575 const SkPaint& paint) {
2576
2577 SkRect storage;
2578 const SkRect* bounds = nullptr;
2579 if (paint.canComputeFastBounds()) {
2580 storage = blob->bounds().makeOffset(x, y);
2581 SkRect tmp;
2582 if (this->quickReject(paint.computeFastBounds(storage, &tmp))) {
2583 return;
2584 }
2585 bounds = &storage;
2586 }
2587
2588 // We cannot filter in the looper as we normally do, because the paint is
2589 // incomplete at this point (text-related attributes are embedded within blob run paints).
2590 SkDrawFilter* drawFilter = fMCRec->fFilter;
2591 fMCRec->fFilter = nullptr;
2592
2593 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, bounds)
2594
2595 while (iter.next()) {
2596 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
2597 iter.fDevice->drawTextBlob(iter, blob, x, y, dfp.paint(), drawFilter);
2598 }
2599
2600 LOOPER_END
2601
2602 fMCRec->fFilter = drawFilter;
2603 }
2604
2605 // These will become non-virtual, so they always call the (virtual) onDraw... method
drawText(const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)2606 void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
2607 const SkPaint& paint) {
2608 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()");
2609 this->onDrawText(text, byteLength, x, y, paint);
2610 }
drawPosText(const void * text,size_t byteLength,const SkPoint pos[],const SkPaint & paint)2611 void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
2612 const SkPaint& paint) {
2613 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()");
2614 this->onDrawPosText(text, byteLength, pos, paint);
2615 }
drawPosTextH(const void * text,size_t byteLength,const SkScalar xpos[],SkScalar constY,const SkPaint & paint)2616 void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
2617 SkScalar constY, const SkPaint& paint) {
2618 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()");
2619 this->onDrawPosTextH(text, byteLength, xpos, constY, paint);
2620 }
drawTextOnPath(const void * text,size_t byteLength,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)2621 void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
2622 const SkMatrix* matrix, const SkPaint& paint) {
2623 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()");
2624 this->onDrawTextOnPath(text, byteLength, path, matrix, paint);
2625 }
drawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)2626 void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
2627 const SkPaint& paint) {
2628 RETURN_ON_NULL(blob);
2629 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextBlob()");
2630 this->onDrawTextBlob(blob, x, y, paint);
2631 }
2632
onDrawVertices(VertexMode vmode,int vertexCount,const SkPoint verts[],const SkPoint texs[],const SkColor colors[],SkXfermode * xmode,const uint16_t indices[],int indexCount,const SkPaint & paint)2633 void SkCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
2634 const SkPoint verts[], const SkPoint texs[],
2635 const SkColor colors[], SkXfermode* xmode,
2636 const uint16_t indices[], int indexCount,
2637 const SkPaint& paint) {
2638 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawVertices()");
2639 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2640
2641 while (iter.next()) {
2642 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
2643 colors, xmode, indices, indexCount,
2644 looper.paint());
2645 }
2646
2647 LOOPER_END
2648 }
2649
drawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkXfermode * xmode,const SkPaint & paint)2650 void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
2651 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2652 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPatch()");
2653 if (nullptr == cubics) {
2654 return;
2655 }
2656
2657 // Since a patch is always within the convex hull of the control points, we discard it when its
2658 // bounding rectangle is completely outside the current clip.
2659 SkRect bounds;
2660 bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
2661 if (this->quickReject(bounds)) {
2662 return;
2663 }
2664
2665 this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
2666 }
2667
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkXfermode * xmode,const SkPaint & paint)2668 void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
2669 const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
2670
2671 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr)
2672
2673 while (iter.next()) {
2674 iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
2675 }
2676
2677 LOOPER_END
2678 }
2679
drawDrawable(SkDrawable * dr,SkScalar x,SkScalar y)2680 void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) {
2681 RETURN_ON_NULL(dr);
2682 if (x || y) {
2683 SkMatrix matrix = SkMatrix::MakeTrans(x, y);
2684 this->onDrawDrawable(dr, &matrix);
2685 } else {
2686 this->onDrawDrawable(dr, nullptr);
2687 }
2688 }
2689
drawDrawable(SkDrawable * dr,const SkMatrix * matrix)2690 void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2691 RETURN_ON_NULL(dr);
2692 if (matrix && matrix->isIdentity()) {
2693 matrix = nullptr;
2694 }
2695 this->onDrawDrawable(dr, matrix);
2696 }
2697
onDrawDrawable(SkDrawable * dr,const SkMatrix * matrix)2698 void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
2699 SkRect bounds = dr->getBounds();
2700 if (matrix) {
2701 matrix->mapRect(&bounds);
2702 }
2703 if (this->quickReject(bounds)) {
2704 return;
2705 }
2706 dr->draw(this, matrix);
2707 }
2708
onDrawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkXfermode::Mode mode,const SkRect * cull,const SkPaint * paint)2709 void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
2710 const SkColor colors[], int count, SkXfermode::Mode mode,
2711 const SkRect* cull, const SkPaint* paint) {
2712 if (cull && this->quickReject(*cull)) {
2713 return;
2714 }
2715
2716 SkPaint pnt;
2717 if (paint) {
2718 pnt = *paint;
2719 }
2720
2721 LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, nullptr)
2722 while (iter.next()) {
2723 iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
2724 }
2725 LOOPER_END
2726 }
2727
2728 //////////////////////////////////////////////////////////////////////////////
2729 // These methods are NOT virtual, and therefore must call back into virtual
2730 // methods, rather than actually drawing themselves.
2731 //////////////////////////////////////////////////////////////////////////////
2732
drawARGB(U8CPU a,U8CPU r,U8CPU g,U8CPU b,SkXfermode::Mode mode)2733 void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
2734 SkXfermode::Mode mode) {
2735 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()");
2736 SkPaint paint;
2737
2738 paint.setARGB(a, r, g, b);
2739 if (SkXfermode::kSrcOver_Mode != mode) {
2740 paint.setXfermodeMode(mode);
2741 }
2742 this->drawPaint(paint);
2743 }
2744
drawColor(SkColor c,SkXfermode::Mode mode)2745 void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
2746 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()");
2747 SkPaint paint;
2748
2749 paint.setColor(c);
2750 if (SkXfermode::kSrcOver_Mode != mode) {
2751 paint.setXfermodeMode(mode);
2752 }
2753 this->drawPaint(paint);
2754 }
2755
drawPoint(SkScalar x,SkScalar y,const SkPaint & paint)2756 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
2757 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkPaint)");
2758 SkPoint pt;
2759
2760 pt.set(x, y);
2761 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2762 }
2763
drawPoint(SkScalar x,SkScalar y,SkColor color)2764 void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
2765 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPoint(SkColor)");
2766 SkPoint pt;
2767 SkPaint paint;
2768
2769 pt.set(x, y);
2770 paint.setColor(color);
2771 this->drawPoints(kPoints_PointMode, 1, &pt, paint);
2772 }
2773
drawLine(SkScalar x0,SkScalar y0,SkScalar x1,SkScalar y1,const SkPaint & paint)2774 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
2775 const SkPaint& paint) {
2776 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawLine()");
2777 SkPoint pts[2];
2778
2779 pts[0].set(x0, y0);
2780 pts[1].set(x1, y1);
2781 this->drawPoints(kLines_PointMode, 2, pts, paint);
2782 }
2783
drawRectCoords(SkScalar left,SkScalar top,SkScalar right,SkScalar bottom,const SkPaint & paint)2784 void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
2785 SkScalar right, SkScalar bottom,
2786 const SkPaint& paint) {
2787 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRectCoords()");
2788 SkRect r;
2789
2790 r.set(left, top, right, bottom);
2791 this->drawRect(r, paint);
2792 }
2793
drawCircle(SkScalar cx,SkScalar cy,SkScalar radius,const SkPaint & paint)2794 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
2795 const SkPaint& paint) {
2796 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawCircle()");
2797 if (radius < 0) {
2798 radius = 0;
2799 }
2800
2801 SkRect r;
2802 r.set(cx - radius, cy - radius, cx + radius, cy + radius);
2803 this->drawOval(r, paint);
2804 }
2805
drawRoundRect(const SkRect & r,SkScalar rx,SkScalar ry,const SkPaint & paint)2806 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
2807 const SkPaint& paint) {
2808 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()");
2809 if (rx > 0 && ry > 0) {
2810 if (paint.canComputeFastBounds()) {
2811 SkRect storage;
2812 if (this->quickReject(paint.computeFastBounds(r, &storage))) {
2813 return;
2814 }
2815 }
2816 SkRRect rrect;
2817 rrect.setRectXY(r, rx, ry);
2818 this->drawRRect(rrect, paint);
2819 } else {
2820 this->drawRect(r, paint);
2821 }
2822 }
2823
drawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)2824 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
2825 SkScalar sweepAngle, bool useCenter,
2826 const SkPaint& paint) {
2827 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
2828 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
2829 this->drawOval(oval, paint);
2830 } else {
2831 SkPath path;
2832 if (useCenter) {
2833 path.moveTo(oval.centerX(), oval.centerY());
2834 }
2835 path.arcTo(oval, startAngle, sweepAngle, !useCenter);
2836 if (useCenter) {
2837 path.close();
2838 }
2839 this->drawPath(path, paint);
2840 }
2841 }
2842
drawTextOnPathHV(const void * text,size_t byteLength,const SkPath & path,SkScalar hOffset,SkScalar vOffset,const SkPaint & paint)2843 void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
2844 const SkPath& path, SkScalar hOffset,
2845 SkScalar vOffset, const SkPaint& paint) {
2846 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPathHV()");
2847 SkMatrix matrix;
2848
2849 matrix.setTranslate(hOffset, vOffset);
2850 this->drawTextOnPath(text, byteLength, path, &matrix, paint);
2851 }
2852
2853 ///////////////////////////////////////////////////////////////////////////////
2854
2855 /**
2856 * This constant is trying to balance the speed of ref'ing a subpicture into a parent picture,
2857 * against the playback cost of recursing into the subpicture to get at its actual ops.
2858 *
2859 * For now we pick a conservatively small value, though measurement (and other heuristics like
2860 * the type of ops contained) may justify changing this value.
2861 */
2862 #define kMaxPictureOpsToUnrollInsteadOfRef 1
2863
drawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2864 void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
2865 RETURN_ON_NULL(picture);
2866
2867 TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPicture()");
2868 if (matrix && matrix->isIdentity()) {
2869 matrix = nullptr;
2870 }
2871 if (picture->approximateOpCount() <= kMaxPictureOpsToUnrollInsteadOfRef) {
2872 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2873 picture->playback(this);
2874 } else {
2875 this->onDrawPicture(picture, matrix, paint);
2876 }
2877 }
2878
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)2879 void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
2880 const SkPaint* paint) {
2881 if (!paint || paint->canComputeFastBounds()) {
2882 SkRect bounds = picture->cullRect();
2883 if (paint) {
2884 paint->computeFastBounds(bounds, &bounds);
2885 }
2886 if (matrix) {
2887 matrix->mapRect(&bounds);
2888 }
2889 if (this->quickReject(bounds)) {
2890 return;
2891 }
2892 }
2893
2894 SkBaseDevice* device = this->getTopDevice();
2895 if (device) {
2896 // Canvas has to first give the device the opportunity to render
2897 // the picture itself.
2898 if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
2899 return; // the device has rendered the entire picture
2900 }
2901 }
2902
2903 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
2904 picture->playback(this);
2905 }
2906
2907 ///////////////////////////////////////////////////////////////////////////////
2908 ///////////////////////////////////////////////////////////////////////////////
2909
LayerIter(SkCanvas * canvas,bool skipEmptyClips)2910 SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
2911 static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
2912
2913 SkASSERT(canvas);
2914
2915 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
2916 fDone = !fImpl->next();
2917 }
2918
~LayerIter()2919 SkCanvas::LayerIter::~LayerIter() {
2920 fImpl->~SkDrawIter();
2921 }
2922
next()2923 void SkCanvas::LayerIter::next() {
2924 fDone = !fImpl->next();
2925 }
2926
device() const2927 SkBaseDevice* SkCanvas::LayerIter::device() const {
2928 return fImpl->getDevice();
2929 }
2930
matrix() const2931 const SkMatrix& SkCanvas::LayerIter::matrix() const {
2932 return fImpl->getMatrix();
2933 }
2934
paint() const2935 const SkPaint& SkCanvas::LayerIter::paint() const {
2936 const SkPaint* paint = fImpl->getPaint();
2937 if (nullptr == paint) {
2938 paint = &fDefaultPaint;
2939 }
2940 return *paint;
2941 }
2942
clip() const2943 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
x() const2944 int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
y() const2945 int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
2946
2947 ///////////////////////////////////////////////////////////////////////////////
2948
~SkCanvasClipVisitor()2949 SkCanvasClipVisitor::~SkCanvasClipVisitor() { }
2950
2951 ///////////////////////////////////////////////////////////////////////////////
2952
supported_for_raster_canvas(const SkImageInfo & info)2953 static bool supported_for_raster_canvas(const SkImageInfo& info) {
2954 switch (info.alphaType()) {
2955 case kPremul_SkAlphaType:
2956 case kOpaque_SkAlphaType:
2957 break;
2958 default:
2959 return false;
2960 }
2961
2962 switch (info.colorType()) {
2963 case kAlpha_8_SkColorType:
2964 case kRGB_565_SkColorType:
2965 case kN32_SkColorType:
2966 break;
2967 default:
2968 return false;
2969 }
2970
2971 return true;
2972 }
2973
NewRasterDirect(const SkImageInfo & info,void * pixels,size_t rowBytes)2974 SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) {
2975 if (!supported_for_raster_canvas(info)) {
2976 return nullptr;
2977 }
2978
2979 SkBitmap bitmap;
2980 if (!bitmap.installPixels(info, pixels, rowBytes)) {
2981 return nullptr;
2982 }
2983 return new SkCanvas(bitmap);
2984 }
2985
2986 ///////////////////////////////////////////////////////////////////////////////
2987
SkAutoCanvasMatrixPaint(SkCanvas * canvas,const SkMatrix * matrix,const SkPaint * paint,const SkRect & bounds)2988 SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
2989 const SkPaint* paint, const SkRect& bounds)
2990 : fCanvas(canvas)
2991 , fSaveCount(canvas->getSaveCount())
2992 {
2993 if (paint) {
2994 SkRect newBounds = bounds;
2995 if (matrix) {
2996 matrix->mapRect(&newBounds);
2997 }
2998 canvas->saveLayer(&newBounds, paint);
2999 } else if (matrix) {
3000 canvas->save();
3001 }
3002
3003 if (matrix) {
3004 canvas->concat(*matrix);
3005 }
3006 }
3007
~SkAutoCanvasMatrixPaint()3008 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3009 fCanvas->restoreToCount(fSaveCount);
3010 }
3011